1 /***************************************************************************//**
2 * @file
3 * @brief Universal synchronous/asynchronous receiver/transmitter (USART/UART)
4 * Peripheral API
5 *******************************************************************************
6 * # License
7 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
8 *******************************************************************************
9 *
10 * SPDX-License-Identifier: Zlib
11 *
12 * The licensor of this software is Silicon Laboratories Inc.
13 *
14 * This software is provided 'as-is', without any express or implied
15 * warranty. In no event will the authors be held liable for any damages
16 * arising from the use of this software.
17 *
18 * Permission is granted to anyone to use this software for any purpose,
19 * including commercial applications, and to alter it and redistribute it
20 * freely, subject to the following restrictions:
21 *
22 * 1. The origin of this software must not be misrepresented; you must not
23 * claim that you wrote the original software. If you use this software
24 * in a product, an acknowledgment in the product documentation would be
25 * appreciated but is not required.
26 * 2. Altered source versions must be plainly marked as such, and must not be
27 * misrepresented as being the original software.
28 * 3. This notice may not be removed or altered from any source distribution.
29 *
30 ******************************************************************************/
31
32 #include "em_usart.h"
33 #if defined(USART_COUNT) && (USART_COUNT > 0)
34
35 #include "em_cmu.h"
36 #include "em_bus.h"
37 #include "em_assert.h"
38 #if defined(USART_CTRLX_CTSEN)
39 #include "em_gpio.h"
40 #endif
41
42 /*******************************************************************************
43 ******************************* DEFINES ***********************************
44 ******************************************************************************/
45
46 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
47
48 /** Validation of USART register block pointer reference for assert statements. */
49 #if (USART_COUNT == 1) && defined(USART0)
50 #define USART_REF_VALID(ref) ((ref) == USART0)
51
52 #elif (USART_COUNT == 1) && defined(USART1)
53 #define USART_REF_VALID(ref) ((ref) == USART1)
54
55 #elif (USART_COUNT == 2) && defined(USART2)
56 #define USART_REF_VALID(ref) (((ref) == USART1) || ((ref) == USART2))
57
58 #elif (USART_COUNT == 2)
59 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
60
61 #elif (USART_COUNT == 3)
62 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) \
63 || ((ref) == USART2))
64 #elif (USART_COUNT == 4)
65 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) \
66 || ((ref) == USART2) || ((ref) == USART3))
67 #elif (USART_COUNT == 5)
68 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) \
69 || ((ref) == USART2) || ((ref) == USART3) \
70 || ((ref) == USART4))
71 #elif (USART_COUNT == 6)
72 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) \
73 || ((ref) == USART2) || ((ref) == USART3) \
74 || ((ref) == USART4) || ((ref) == USART5))
75 #else
76 #error "Undefined number of USARTs."
77 #endif
78
79 #if defined(USARTRF_COUNT) && (USARTRF_COUNT > 0)
80 #if (USARTRF_COUNT == 1) && defined(USARTRF0)
81 #define USARTRF_REF_VALID(ref) ((ref) == USARTRF0)
82 #elif (USARTRF_COUNT == 1) && defined(USARTRF1)
83 #define USARTRF_REF_VALID(ref) ((ref) == USARTRF1)
84 #else
85 #define USARTRF_REF_VALID(ref) (0)
86 #endif
87 #else
88 #define USARTRF_REF_VALID(ref) (0)
89 #endif
90
91 #if (_SILICON_LABS_32B_SERIES == 2)
92 #define USART_IRDA_VALID(ref) USART_REF_VALID(ref)
93 #elif defined(_SILICON_LABS_32B_SERIES_1)
94 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_100) || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_103)
95 // If GG11 or TG11
96 #define USART_IRDA_VALID(ref) (((ref) == USART0) || ((ref) == USART2))
97 #elif defined(USART3)
98 #define USART_IRDA_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || ((ref) == USART2) || ((ref) == USART3))
99 #elif defined(USART2)
100 #define USART_IRDA_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || ((ref) == USART2))
101 #else
102 #define USART_IRDA_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
103 #endif
104 #elif defined(_SILICON_LABS_32B_SERIES_0)
105 #if defined(_EZR32_HAPPY_FAMILY)
106 #define USART_IRDA_VALID(ref) ((ref) == USART0)
107 #elif defined(_EFM32_HAPPY_FAMILY)
108 #define USART_IRDA_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
109 #elif defined(USART0)
110 #define USART_IRDA_VALID(ref) ((ref) == USART0)
111 #elif (USART_COUNT == 1) && defined(USART1)
112 #define USART_IRDA_VALID(ref) ((ref) == USART1)
113 #elif defined(USARTRF0)
114 #define USART_IRDA_VALID(ref) ((ref) == USARTRF0)
115 #else
116 #define USART_IRDA_VALID(ref) (0)
117 #endif
118 #endif
119
120 #if (_SILICON_LABS_32B_SERIES == 2)
121 #define USART_I2S_VALID(ref) USART_REF_VALID(ref)
122 #elif defined(_SILICON_LABS_32B_SERIES_1)
123 #if defined(USART4)
124 #define USART_I2S_VALID(ref) (((ref) == USART1) || ((ref) == USART3) || ((ref) == USART4))
125 #elif defined(USART3)
126 #define USART_I2S_VALID(ref) (((ref) == USART1) || ((ref) == USART3))
127 #else
128 #define USART_I2S_VALID(ref) ((ref) == USART1)
129 #endif
130 #elif defined(_SILICON_LABS_32B_SERIES_0)
131 #if defined(_EZR32_HAPPY_FAMILY)
132 #define USART_I2S_VALID(ref) ((ref) == USART0)
133 #elif defined(_EFM32_HAPPY_FAMILY)
134 #define USART_I2S_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
135 #elif defined(_EFM32_TINY_FAMILY) || defined(_EFM32_ZERO_FAMILY)
136 #define USART_I2S_VALID(ref) ((ref) == USART1)
137 #elif defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
138 #define USART_I2S_VALID(ref) (((ref) == USART1) || ((ref) == USART2))
139 #endif
140 #endif
141
142 #if (UART_COUNT == 1) && !defined(_UART_IPVERSION_MASK)
143 #define UART_REF_VALID(ref) ((ref) == UART0)
144 #elif (UART_COUNT == 2) && !defined(_UART_IPVERSION_MASK)
145 #define UART_REF_VALID(ref) (((ref) == UART0) || ((ref) == UART1))
146 #else
147 #define UART_REF_VALID(ref) (0)
148 #endif
149
150 #if defined(_USART_CLKDIV_DIVEXT_MASK)
151 #define CLKDIV_MASK (_USART_CLKDIV_DIV_MASK | _USART_CLKDIV_DIVEXT_MASK)
152 #else
153 #define CLKDIV_MASK _USART_CLKDIV_DIV_MASK
154 #endif
155
156 /** @endcond */
157
158 /*******************************************************************************
159 ************************** LOCAL FUNCTIONS ********************************
160 ******************************************************************************/
161
162 #if !defined(_EFM32_GECKO_FAMILY)
163 /***************************************************************************//**
164 * @brief
165 * Configure a PRS channel as USART Rx input
166 *
167 * @param[in] usart
168 * A pointer to the USART/UART peripheral register block.
169 *
170 * @param[in] ch
171 * PRS channel.
172 ******************************************************************************/
prsRxInput(USART_TypeDef * usart,USART_PRS_Channel_t ch)173 static void prsRxInput(USART_TypeDef *usart, USART_PRS_Channel_t ch)
174 {
175 #if defined(_USART_INPUT_MASK)
176 usart->INPUT = ((uint32_t)ch << _USART_INPUT_RXPRSSEL_SHIFT)
177 | USART_INPUT_RXPRS;
178 #elif defined(USART_CTRLX_RXPRSEN)
179 if (usart == USART0) {
180 PRS->CONSUMER_USART0_RX = ch;
181 }
182 #if defined(USART1)
183 else if (usart == USART1) {
184 PRS->CONSUMER_USART1_RX = ch;
185 }
186 #endif
187 #if defined(USART2)
188 else if (usart == USART2) {
189 PRS->CONSUMER_USART2_RX = ch;
190 }
191 #endif
192 usart->CTRLX |= USART_CTRLX_RXPRSEN;
193 #endif
194 }
195 #endif
196
197 #if defined(USART_IRCTRL_IRPRSEN)
198 /***************************************************************************//**
199 * @brief
200 * Configure a PRS channel as USART Ir input
201 *
202 * @param[in] usart
203 * A pointer to the USART/UART peripheral register block.
204 *
205 * @param[in] ch
206 * PRS channel.
207 ******************************************************************************/
prsIrInput(USART_TypeDef * usart,USART_PRS_Channel_t ch)208 static void prsIrInput(USART_TypeDef *usart, USART_PRS_Channel_t ch)
209 {
210 #if defined(_USART_IRCTRL_IRPRSSEL_SHIFT)
211 usart->IRCTRL |= ((uint32_t)ch << _USART_IRCTRL_IRPRSSEL_SHIFT)
212 | USART_IRCTRL_IRPRSEN;
213 #else
214 (void)ch;
215 usart->IRCTRL |= USART_IRCTRL_IRPRSEN;
216 #endif
217 }
218 #endif
219
220 #if defined(USART_IRCTRL_IRPRSEN) && defined(CONSUMER_USART0_IR)
221 /***************************************************************************//**
222 * @brief
223 * Configure a PRS channel as USART Ir input
224 *
225 * @param[in] usart
226 * A pointer to the USART/UART peripheral register block.
227 *
228 * @param[in] ch
229 * PRS channel.
230 ******************************************************************************/
prsIrInput(USART_TypeDef * usart,USART_PRS_Channel_t ch)231 static void prsIrInput(USART_TypeDef *usart, USART_PRS_Channel_t ch)
232 {
233 if (usart == USART0) {
234 PRS->CONSUMER_USART0_IR = ch;
235 }
236 #if defined(USART1)
237 else if (usart == USART1) {
238 PRS->CONSUMER_USART1_IR = ch;
239 }
240 #endif
241 #if defined(USART2)
242 else if (usart == USART2) {
243 PRS->CONSUMER_USART2_IR = ch;
244 }
245 #endif
246 usart->IRCTRL |= USART_IRCTRL_IRPRSEN;
247 }
248 #endif
249
250 /***************************************************************************//**
251 * @brief
252 * Configure a PRS channel as USART Trigger input
253 *
254 * @param[in] usart
255 * A pointer to the USART/UART peripheral register block.
256 *
257 * @param[in] ch
258 * PRS channel.
259 ******************************************************************************/
prsTriggerInput(USART_TypeDef * usart,USART_PRS_Channel_t ch)260 static void prsTriggerInput(USART_TypeDef *usart, USART_PRS_Channel_t ch)
261 {
262 #if defined(_USART_IRCTRL_IRPRSSEL_MASK)
263 usart->TRIGCTRL = (usart->TRIGCTRL & ~_USART_TRIGCTRL_TSEL_MASK)
264 | (ch << _USART_TRIGCTRL_TSEL_SHIFT);
265 #else
266 if (usart == USART0) {
267 PRS->CONSUMER_USART0_TRIGGER = ch;
268 }
269 #if USART_COUNT > 1
270 else if (usart == USART1) {
271 PRS->CONSUMER_USART1_TRIGGER = ch;
272 }
273 #endif
274 #if USART_COUNT > 2
275 else if (usart == USART2) {
276 PRS->CONSUMER_USART2_TRIGGER = ch;
277 }
278 #endif
279 #endif
280 }
281
282 /*******************************************************************************
283 ************************** GLOBAL FUNCTIONS *******************************
284 ******************************************************************************/
285
286 /***************************************************************************//**
287 * @addtogroup usart
288 * @{
289 ******************************************************************************/
290
291 /***************************************************************************//**
292 * @brief
293 * Configure USART/UART operating in asynchronous mode to use a given
294 * baudrate (or as close as possible to a specified baudrate).
295 *
296 * @param[in] usart
297 * A pointer to the USART/UART peripheral register block.
298 *
299 * @param[in] refFreq
300 * USART/UART reference clock frequency in Hz. If set to 0,
301 * the currently configured reference clock is assumed.
302 *
303 * @param[in] baudrate
304 * Baudrate to try to achieve for USART/UART.
305 *
306 * @param[in] ovs
307 * Oversampling to be used. Normal is 16x oversampling but lower oversampling
308 * may be used to achieve higher rates or better baudrate accuracy in some
309 * cases. Notice that lower oversampling frequency makes the channel more
310 * vulnerable to bit faults during reception due to clock inaccuracies
311 * compared to the link partner.
312 ******************************************************************************/
USART_BaudrateAsyncSet(USART_TypeDef * usart,uint32_t refFreq,uint32_t baudrate,USART_OVS_TypeDef ovs)313 void USART_BaudrateAsyncSet(USART_TypeDef *usart,
314 uint32_t refFreq,
315 uint32_t baudrate,
316 USART_OVS_TypeDef ovs)
317 {
318 uint32_t clkdiv;
319 uint32_t oversample;
320
321 /* Inhibit divide by 0 */
322 EFM_ASSERT(baudrate);
323
324 /*
325 * Use integer division to avoid forcing in float division
326 * utils and yet keep rounding effect errors to a minimum.
327 *
328 * CLKDIV in asynchronous mode is given by:
329 *
330 * CLKDIV = 256 * (fHFPERCLK/(oversample * br) - 1)
331 * or
332 * CLKDIV = (256 * fHFPERCLK)/(oversample * br) - 256
333 *
334 * The basic problem with integer division in the above formula is that
335 * the dividend (256 * fHFPERCLK) may become higher than max 32 bit
336 * integer. Yet, we want to evaluate the dividend first before dividing
337 * to get as small rounding effects as possible.
338 * Too harsh restrictions on maximum fHFPERCLK value should not be made.
339 *
340 * It is possible to factorize 256 and oversample/br. However,
341 * since the last 6 or 3 bits of CLKDIV are don't care, base the
342 * integer arithmetic on the below formula
343 *
344 * CLKDIV / 64 = (4 * fHFPERCLK)/(oversample * br) - 4 (3 bits dont care)
345 * or
346 * CLKDIV / 8 = (32 * fHFPERCLK)/(oversample * br) - 32 (6 bits dont care)
347 *
348 * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK
349 * up to 1 GHz without overflowing a 32 bit value.
350 */
351
352 /* HFPERCLK/HFPERBCLK used to clock all USART/UART peripheral modules. */
353 if (!refFreq) {
354 #if defined(_SILICON_LABS_32B_SERIES_2)
355 refFreq = CMU_ClockFreqGet(cmuClock_PCLK);
356 #else
357 #if defined(_CMU_HFPERPRESCB_MASK)
358 if (usart == USART2) {
359 refFreq = CMU_ClockFreqGet(cmuClock_HFPERB);
360 } else {
361 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
362 }
363 #else
364 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
365 #endif
366 #endif
367 }
368
369 /* Map oversampling. */
370 switch (ovs) {
371 case usartOVS16:
372 EFM_ASSERT(baudrate <= (refFreq / 16));
373 oversample = 16;
374 break;
375
376 case usartOVS8:
377 EFM_ASSERT(baudrate <= (refFreq / 8));
378 oversample = 8;
379 break;
380
381 case usartOVS6:
382 EFM_ASSERT(baudrate <= (refFreq / 6));
383 oversample = 6;
384 break;
385
386 case usartOVS4:
387 EFM_ASSERT(baudrate <= (refFreq / 4));
388 oversample = 4;
389 break;
390
391 default:
392 /* Invalid input */
393 EFM_ASSERT(0);
394 return;
395 }
396
397 /* Calculate and set CLKDIV with fractional bits.
398 * The added (oversample*baudrate)/2 in the first line is to round the
399 * divisor to the nearest fractional divisor. */
400 #if defined(_SILICON_LABS_32B_SERIES_0) && !defined(_EFM32_HAPPY_FAMILY)
401 /* Devices with 2 fractional bits. CLKDIV[7:6] */
402 clkdiv = 4 * refFreq + (oversample * baudrate) / 2;
403 clkdiv /= oversample * baudrate;
404 clkdiv -= 4;
405 clkdiv *= 64;
406 #else
407 /* Devices with 5 fractional bits. CLKDIV[7:3] */
408 clkdiv = 32 * refFreq + (oversample * baudrate) / 2;
409 clkdiv /= oversample * baudrate;
410 clkdiv -= 32;
411 clkdiv *= 8;
412 #endif
413
414 /* Verify that the resulting clock divider is within limits. */
415 EFM_ASSERT(clkdiv <= CLKDIV_MASK);
416
417 /* Make sure that reserved bits are not written to. */
418 clkdiv &= CLKDIV_MASK;
419
420 usart->CTRL &= ~_USART_CTRL_OVS_MASK;
421 usart->CTRL |= ovs;
422 usart->CLKDIV = clkdiv;
423 }
424
425 /***************************************************************************//**
426 * @brief
427 * Calculate baudrate for USART/UART given reference frequency, clock division,
428 * and oversampling rate (if async mode).
429 *
430 * @details
431 * This function returns the baudrate that a USART/UART module will use if
432 * configured with the given frequency, clock divisor, and mode. Notice that
433 * this function will not use the hardware configuration. It can be used
434 * to determine if a given configuration is sufficiently accurate for the
435 * application.
436 *
437 * @param[in] refFreq
438 * USART/UART HF peripheral frequency used.
439 *
440 * @param[in] clkdiv
441 * A clock division factor to be used.
442 *
443 * @param[in] syncmode
444 * @li True - synchronous mode operation.
445 * @li False - asynchronous mode operation.
446 *
447 * @param[in] ovs
448 * Oversampling used if in asynchronous mode. Not used if @p syncmode is true.
449 *
450 * @return
451 * Baudrate with given settings.
452 ******************************************************************************/
USART_BaudrateCalc(uint32_t refFreq,uint32_t clkdiv,bool syncmode,USART_OVS_TypeDef ovs)453 uint32_t USART_BaudrateCalc(uint32_t refFreq,
454 uint32_t clkdiv,
455 bool syncmode,
456 USART_OVS_TypeDef ovs)
457 {
458 uint32_t oversample;
459 uint64_t divisor;
460 uint64_t factor;
461 uint64_t remainder;
462 uint64_t quotient;
463 uint32_t br;
464
465 /* Out of bound clkdiv. */
466 EFM_ASSERT(clkdiv <= CLKDIV_MASK);
467
468 /* Mask out unused bits */
469 clkdiv &= CLKDIV_MASK;
470
471 /* Use integer division to avoid forcing in float division */
472 /* utils and yet keep rounding effect errors to a minimum. */
473
474 /* Baudrate calculation depends on if synchronous or asynchronous mode. */
475 if (syncmode) {
476 /*
477 * Baudrate is given by:
478 *
479 * br = fHFPERCLK/(2 * (1 + (CLKDIV / 256)))
480 *
481 * which can be rewritten to
482 *
483 * br = (128 * fHFPERCLK)/(256 + CLKDIV)
484 */
485 oversample = 1; /* Not used in sync mode, i.e., 1 */
486 factor = 128;
487 } else {
488 /*
489 * Baudrate in asynchronous mode is given by:
490 *
491 * br = fHFPERCLK/(oversample * (1 + (CLKDIV / 256)))
492 *
493 * which can be rewritten to
494 *
495 * br = (256 * fHFPERCLK)/(oversample * (256 + CLKDIV))
496 *
497 * 256 factor of the dividend is reduced with a
498 * (part of) oversample part of the divisor.
499 */
500
501 switch (ovs) {
502 case usartOVS16:
503 oversample = 1;
504 factor = 256 / 16;
505 break;
506
507 case usartOVS8:
508 oversample = 1;
509 factor = 256 / 8;
510 break;
511
512 case usartOVS6:
513 oversample = 3;
514 factor = 256 / 2;
515 break;
516
517 default:
518 oversample = 1;
519 factor = 256 / 4;
520 break;
521 }
522 }
523
524 /*
525 * The basic problem with integer division in the above formula is that
526 * the dividend (factor * fHFPERCLK) may become larger than a 32 bit
527 * integer. Yet we want to evaluate the dividend first before dividing
528 * to get as small rounding effects as possible. Too harsh restrictions
529 * should not be made on the maximum fHFPERCLK value either.
530 *
531 * For division a/b,
532 *
533 * a = qb + r
534 *
535 * where q is the quotient and r is the remainder, both integers.
536 *
537 * The original baudrate formula can be rewritten as
538 *
539 * br = xa / b = x(qb + r)/b = xq + xr/b
540 *
541 * where x is 'factor', a is 'refFreq' and b is 'divisor', referring to
542 * variable names.
543 */
544
545 /*
546 * The divisor will never exceed max 32 bit value since
547 * clkdiv <= _USART_CLKDIV_DIV_MASK (currently 0x1FFFC0 or 0x7FFFF8)
548 * and 'oversample' has been reduced to <= 3.
549 */
550 divisor = oversample * (256 + clkdiv);
551
552 quotient = refFreq / divisor;
553 remainder = refFreq % divisor;
554
555 /* The factor <= 128 and since divisor >= 256, the below cannot exceed the maximum */
556 /* 32 bit value. However, factor * remainder can become larger than 32-bit */
557 /* because of the size of _USART_CLKDIV_DIV_MASK on some families. */
558 br = (uint32_t)(factor * quotient);
559
560 /*
561 * The factor <= 128 and remainder < (oversample*(256 + clkdiv)), which
562 * means dividend (factor * remainder) worst case is
563 * 128 * (3 * (256 + _USART_CLKDIV_DIV_MASK)) = 0x1_8001_7400.
564 */
565 br += (uint32_t)((factor * remainder) / divisor);
566
567 return br;
568 }
569
570 /***************************************************************************//**
571 * @brief
572 * Get the current baudrate for USART/UART.
573 *
574 * @details
575 * This function returns the actual baudrate (not considering oscillator
576 * inaccuracies) used by a USART/UART peripheral.
577 *
578 * @param[in] usart
579 * A pointer to the USART/UART peripheral register block.
580 *
581 * @return
582 * The current baudrate.
583 ******************************************************************************/
USART_BaudrateGet(USART_TypeDef * usart)584 uint32_t USART_BaudrateGet(USART_TypeDef *usart)
585 {
586 uint32_t freq;
587 USART_OVS_TypeDef ovs;
588 bool syncmode;
589
590 if (usart->CTRL & USART_CTRL_SYNC) {
591 syncmode = true;
592 } else {
593 syncmode = false;
594 }
595
596 /* HFPERCLK/HFPERBCLK used to clock all USART/UART peripheral modules. */
597 #if defined(_SILICON_LABS_32B_SERIES_2)
598 freq = CMU_ClockFreqGet(cmuClock_PCLK);
599 #else
600 #if defined(_CMU_HFPERPRESCB_MASK)
601 if (usart == USART2) {
602 freq = CMU_ClockFreqGet(cmuClock_HFPERB);
603 } else {
604 freq = CMU_ClockFreqGet(cmuClock_HFPER);
605 }
606 #else
607 freq = CMU_ClockFreqGet(cmuClock_HFPER);
608 #endif
609 #endif
610 ovs = (USART_OVS_TypeDef)(usart->CTRL & _USART_CTRL_OVS_MASK);
611 return USART_BaudrateCalc(freq, usart->CLKDIV, syncmode, ovs);
612 }
613
614 /***************************************************************************//**
615 * @brief
616 * Configure the USART operating in synchronous mode to use a given baudrate
617 * (or as close as possible to a specified baudrate).
618 *
619 * @details
620 * The configuration will be set to use a baudrate <= the specified baudrate
621 * to ensure that the baudrate does not exceed the specified value.
622 *
623 * The fractional clock division is suppressed, although the hardware design allows it.
624 * It could cause half clock cycles to exceed a specified limit and thus
625 * potentially violate specifications for the slave device. In some special
626 * situations, a fractional clock division may be useful even in synchronous
627 * mode, but in those cases it must be directly adjusted, possibly assisted
628 * by USART_BaudrateCalc():
629 *
630 * @param[in] usart
631 * A pointer to the USART peripheral register block. (Cannot be used on UART
632 * modules.)
633 *
634 * @param[in] refFreq
635 * A USART reference clock frequency in Hz that will be used. If set to 0,
636 * the currently-configured reference clock is assumed.
637 *
638 * @param[in] baudrate
639 * Baudrate to try to achieve for USART.
640 ******************************************************************************/
USART_BaudrateSyncSet(USART_TypeDef * usart,uint32_t refFreq,uint32_t baudrate)641 void USART_BaudrateSyncSet(USART_TypeDef *usart, uint32_t refFreq, uint32_t baudrate)
642 {
643 uint32_t clkdiv;
644
645 /* Prevent dividing by 0. */
646 EFM_ASSERT(baudrate);
647
648 /*
649 * CLKDIV in synchronous mode is given by:
650 *
651 * CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1)
652 */
653
654 /* HFPERCLK/HFPERBCLK used to clock all USART/UART peripheral modules. */
655 if (!refFreq) {
656 #if defined(_SILICON_LABS_32B_SERIES_2)
657 refFreq = CMU_ClockFreqGet(cmuClock_PCLK);
658 #else
659 #if defined(_CMU_HFPERPRESCB_MASK)
660 if (usart == USART2) {
661 refFreq = CMU_ClockFreqGet(cmuClock_HFPERB);
662 } else {
663 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
664 }
665 #else
666 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
667 #endif
668 #endif
669 }
670
671 clkdiv = (refFreq - 1) / (2 * baudrate);
672 clkdiv = clkdiv << 8;
673
674 /* Verify that resulting clock divider is within limits. */
675 EFM_ASSERT(!(clkdiv & ~CLKDIV_MASK));
676
677 usart->CLKDIV = clkdiv;
678 }
679
680 /***************************************************************************//**
681 * @brief
682 * Enable/disable USART/UART receiver and/or transmitter.
683 *
684 * @details
685 * Notice that this function does not do any configuration. Enabling should
686 * normally be done after initialization (if not enabled as part
687 * of initialization).
688 *
689 * @param[in] usart
690 * A pointer to the USART/UART peripheral register block.
691 *
692 * @param[in] enable
693 * Select the status for the receiver/transmitter.
694 ******************************************************************************/
USART_Enable(USART_TypeDef * usart,USART_Enable_TypeDef enable)695 void USART_Enable(USART_TypeDef *usart, USART_Enable_TypeDef enable)
696 {
697 uint32_t tmp;
698
699 /* Make sure the module exists on the selected chip. */
700 EFM_ASSERT(USART_REF_VALID(usart)
701 || USARTRF_REF_VALID(usart)
702 || UART_REF_VALID(usart));
703
704 #if defined(USART_EN_EN)
705 usart->EN_SET = USART_EN_EN;
706 #endif
707
708 /* Disable as specified. */
709 tmp = ~((uint32_t)enable);
710 tmp &= _USART_CMD_RXEN_MASK | _USART_CMD_TXEN_MASK;
711 usart->CMD = tmp << 1;
712
713 /* Enable as specified. */
714 usart->CMD = (uint32_t)enable;
715
716 #if defined(USART_EN_EN)
717 if (enable == usartDisable) {
718 usart->EN_CLR = USART_EN_EN;
719 }
720 #endif
721 }
722
723 /***************************************************************************//**
724 * @brief
725 * Initialize USART/UART for normal asynchronous mode.
726 *
727 * @details
728 * This function will configure basic settings to operate in normal
729 * asynchronous mode.
730 *
731 * A special control setup not covered by this function must be done after
732 * using this function by direct modification of the CTRL register.
733 *
734 * Notice that pins used by the USART/UART module must be properly configured
735 * by the user explicitly for the USART/UART to work as intended.
736 * (When configuring pins, remember to consider the sequence of
737 * configuration to avoid unintended pulses/glitches on output
738 * pins.)
739 *
740 * @param[in] usart
741 * A pointer to the USART/UART peripheral register block.
742 *
743 * @param[in] init
744 * A pointer to the initialization structure used to configure the basic async setup.
745 ******************************************************************************/
USART_InitAsync(USART_TypeDef * usart,const USART_InitAsync_TypeDef * init)746 void USART_InitAsync(USART_TypeDef *usart, const USART_InitAsync_TypeDef *init)
747 {
748 /* Make sure the module exists on the selected chip. */
749 EFM_ASSERT(USART_REF_VALID(usart)
750 || USARTRF_REF_VALID(usart)
751 || UART_REF_VALID(usart));
752
753 /* Initialize USART registers to hardware reset state. */
754 USART_Reset(usart);
755
756 #if defined(USART_EN_EN)
757 usart->EN_SET = USART_EN_EN;
758 #endif
759
760 #if defined(USART_CTRL_MVDIS)
761 /* Disable the majority vote if specified. */
762 if (init->mvdis) {
763 usart->CTRL |= USART_CTRL_MVDIS;
764 }
765 #endif
766
767 #if !defined(_EFM32_GECKO_FAMILY)
768 /* Configure the PRS input mode. */
769 if (init->prsRxEnable) {
770 prsRxInput(usart, init->prsRxCh);
771 }
772 #endif
773
774 /* Configure databits, stopbits, and parity. */
775 usart->FRAME = (uint32_t)init->databits
776 | (uint32_t)init->stopbits
777 | (uint32_t)init->parity;
778
779 /* Configure baudrate. */
780 USART_BaudrateAsyncSet(usart, init->refFreq, init->baudrate, init->oversampling);
781
782 if (init->autoCsEnable) {
783 usart->CTRL |= USART_CTRL_AUTOCS;
784 }
785 #if defined(_USART_TIMING_CSHOLD_MASK)
786 usart->TIMING = ((init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
787 & _USART_TIMING_CSHOLD_MASK)
788 | ((init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
789 & _USART_TIMING_CSSETUP_MASK);
790
791 #endif
792
793 #if defined(_USART_ROUTEPEN_RTSPEN_MASK) && defined(_USART_ROUTEPEN_CTSPEN_MASK)
794 usart->ROUTEPEN &= ~(_USART_ROUTEPEN_RTSPEN_MASK | _USART_ROUTEPEN_CTSPEN_MASK);
795 usart->ROUTEPEN |= init->hwFlowControl;
796
797 #elif defined(USART_CTRLX_CTSEN)
798 if ((init->hwFlowControl == usartHwFlowControlRts)
799 || (init->hwFlowControl == usartHwFlowControlCtsAndRts)) {
800 #if USART_COUNT > 1
801 GPIO->USARTROUTE_SET[USART_NUM(usart)].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
802 #else
803 //! @todo cleanup when ADM is updated to have USART_NUM macros
804 GPIO->USARTROUTE_SET[0].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
805 #endif
806 } else {
807 #if USART_COUNT > 1
808 GPIO->USARTROUTE_CLR[USART_NUM(usart)].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
809 #else
810 //! @todo cleanup when ADM is updated to have USART_NUM macros
811 GPIO->USARTROUTE_CLR[0].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
812 #endif
813 }
814
815 if ((init->hwFlowControl == usartHwFlowControlCts)
816 || (init->hwFlowControl == usartHwFlowControlCtsAndRts)) {
817 usart->CTRLX_SET = USART_CTRLX_CTSEN;
818 } else {
819 usart->CTRLX_CLR = USART_CTRLX_CTSEN;
820 }
821 #endif
822
823 /* Finally, enable (as specified). */
824 usart->CMD = (uint32_t)init->enable;
825 }
826
827 /***************************************************************************//**
828 * @brief
829 * Initialize USART for synchronous mode.
830 *
831 * @details
832 * This function will configure basic settings to operate in
833 * synchronous mode.
834 *
835 * A special control setup not covered by this function must be done after
836 * using this function by direct modification of the CTRL register.
837 *
838 * Notice that pins used by the USART module must be properly configured
839 * by the user explicitly for the USART to work as intended.
840 * (When configuring pins remember to consider the sequence of
841 * configuration to avoid unintended pulses/glitches on output
842 * pins.)
843 *
844 * @param[in] usart
845 * A pointer to the USART peripheral register block. (UART does not support this
846 * mode.)
847 *
848 * @param[in] init
849 * A pointer to the initialization structure used to configure basic async setup.
850 ******************************************************************************/
USART_InitSync(USART_TypeDef * usart,const USART_InitSync_TypeDef * init)851 void USART_InitSync(USART_TypeDef *usart, const USART_InitSync_TypeDef *init)
852 {
853 /* Make sure the module exists on the selected chip. */
854 EFM_ASSERT(USART_REF_VALID(usart) || USARTRF_REF_VALID(usart) );
855
856 /* Initialize USART registers to hardware reset state. */
857 USART_Reset(usart);
858
859 #if defined(USART_EN_EN)
860 usart->EN_SET = USART_EN_EN;
861 #endif
862
863 /* Set bits for synchronous mode. */
864 usart->CTRL |= (USART_CTRL_SYNC)
865 | (uint32_t)init->clockMode
866 | (init->msbf ? USART_CTRL_MSBF : 0);
867
868 #if defined(_USART_CTRL_AUTOTX_MASK)
869 usart->CTRL |= init->autoTx ? USART_CTRL_AUTOTX : 0;
870 #endif
871
872 #if !defined(_EFM32_GECKO_FAMILY)
873 if (init->prsRxEnable) {
874 prsRxInput(usart, init->prsRxCh);
875 }
876 #endif
877
878 /* Configure databits, leave stopbits and parity at reset default (not used). */
879 usart->FRAME = (uint32_t)init->databits
880 | USART_FRAME_STOPBITS_DEFAULT
881 | USART_FRAME_PARITY_DEFAULT;
882
883 /* Configure the baudrate. */
884 USART_BaudrateSyncSet(usart, init->refFreq, init->baudrate);
885
886 /* Finally, enable (as specified). */
887 if (init->master) {
888 usart->CMD = USART_CMD_MASTEREN;
889 }
890
891 if (init->autoCsEnable) {
892 usart->CTRL |= USART_CTRL_AUTOCS;
893 }
894 #if defined(_USART_TIMING_CSHOLD_MASK)
895 usart->TIMING = ((init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
896 & _USART_TIMING_CSHOLD_MASK)
897 | ((init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
898 & _USART_TIMING_CSSETUP_MASK);
899 #endif
900
901 usart->CMD = (uint32_t)init->enable;
902 }
903
904 /***************************************************************************//**
905 * @brief
906 * Initialize USART for asynchronous IrDA mode.
907 *
908 * @details
909 * This function will configure basic settings to operate in
910 * asynchronous IrDA mode.
911 *
912 * A special control setup not covered by this function must be done after
913 * using this function by direct modification of the CTRL and IRCTRL
914 * registers.
915 *
916 * Notice that pins used by the USART/UART module must be properly configured
917 * by the user explicitly for the USART/UART to work as intended.
918 * (When configuring pins, remember to consider the sequence of
919 * configuration to avoid unintended pulses/glitches on output
920 * pins.)
921 *
922 * @param[in] usart
923 * A pointer to the USART peripheral register block.
924 *
925 * @param[in] init
926 * A pointer to the initialization structure used to configure async IrDA setup.
927 *
928 * @note
929 * Not all USART instances support IrDA. See the data sheet for your device.
930 *
931 ******************************************************************************/
USARTn_InitIrDA(USART_TypeDef * usart,const USART_InitIrDA_TypeDef * init)932 void USARTn_InitIrDA(USART_TypeDef *usart, const USART_InitIrDA_TypeDef *init)
933 {
934 EFM_ASSERT(USART_IRDA_VALID(usart));
935
936 /* Initialize USART as an async device. */
937 USART_InitAsync(usart, &(init->async));
938
939 /* Set IrDA modulation to RZI (return-to-zero-inverted). */
940 usart->CTRL |= USART_CTRL_TXINV;
941
942 /* Invert the Rx signal before the demodulator if enabled. */
943 if (init->irRxInv) {
944 usart->CTRL |= USART_CTRL_RXINV;
945 }
946
947 /* Configure IrDA. */
948 usart->IRCTRL = (uint32_t)init->irPw
949 | ((init->irFilt ? 1UL : 0UL) << _USART_IRCTRL_IRFILT_SHIFT);
950
951 #if defined(USART_IRCTRL_IRPRSEN)
952 if (init->irPrsEn) {
953 prsIrInput(usart, init->irPrsSel);
954 }
955 #endif
956
957 /* Enable IrDA. */
958 usart->IRCTRL |= USART_IRCTRL_IREN;
959 }
960
961 #if defined(_USART_I2SCTRL_MASK)
962 /***************************************************************************//**
963 * @brief
964 * Initialize USART for I2S mode.
965 *
966 * @details
967 * This function will configure basic settings to operate in I2S
968 * mode.
969 *
970 * A special control setup not covered by this function must be done after
971 * using this function by direct modification of the CTRL and I2SCTRL
972 * registers.
973 *
974 * Notice that pins used by the USART module must be properly configured
975 * by the user explicitly for the USART to work as intended.
976 * (When configuring pins, remember to consider the sequence of
977 * configuration to avoid unintended pulses/glitches on output
978 * pins.)
979 *
980 * @param[in] usart
981 * A pointer to the USART peripheral register block. (UART does not support this
982 * mode.)
983 *
984 * @param[in] init
985 * A pointer to the initialization structure used to configure the basic I2S setup.
986 *
987 * @note
988 * This function does not apply to all USART's. See the chip Reference Manual.
989 *
990 ******************************************************************************/
USART_InitI2s(USART_TypeDef * usart,USART_InitI2s_TypeDef * init)991 void USART_InitI2s(USART_TypeDef *usart, USART_InitI2s_TypeDef *init)
992 {
993 USART_Enable_TypeDef enable;
994
995 /* Make sure the module exists on the selected chip. */
996 EFM_ASSERT(USART_I2S_VALID(usart));
997
998 /* Override the enable setting. */
999 enable = init->sync.enable;
1000 init->sync.enable = usartDisable;
1001
1002 /* Initialize USART as a sync device. */
1003 USART_InitSync(usart, &init->sync);
1004
1005 /* Configure and enable I2CCTRL register according to the selected mode. */
1006 usart->I2SCTRL = (uint32_t)init->format
1007 | (uint32_t)init->justify
1008 | (init->delay ? USART_I2SCTRL_DELAY : 0)
1009 | (init->dmaSplit ? USART_I2SCTRL_DMASPLIT : 0)
1010 | (init->mono ? USART_I2SCTRL_MONO : 0)
1011 | USART_I2SCTRL_EN;
1012
1013 if (enable != usartDisable) {
1014 USART_Enable(usart, enable);
1015 }
1016 }
1017 #endif
1018
1019 /***************************************************************************//**
1020 * @brief
1021 * Initialize the automatic transmissions using PRS channel as a trigger.
1022 * @note
1023 * Initialize USART with USART_Init() before setting up the PRS configuration.
1024 *
1025 * @param[in] usart A pointer to USART to configure.
1026 * @param[in] init A pointer to the initialization structure.
1027 ******************************************************************************/
USART_InitPrsTrigger(USART_TypeDef * usart,const USART_PrsTriggerInit_TypeDef * init)1028 void USART_InitPrsTrigger(USART_TypeDef *usart, const USART_PrsTriggerInit_TypeDef *init)
1029 {
1030 uint32_t trigctrl;
1031
1032 prsTriggerInput(usart, init->prsTriggerChannel);
1033 /* Clear values that will be reconfigured. */
1034 trigctrl = usart->TRIGCTRL & ~(_USART_TRIGCTRL_RXTEN_MASK
1035 | _USART_TRIGCTRL_TXTEN_MASK
1036 #if defined(USART_TRIGCTRL_AUTOTXTEN)
1037 | _USART_TRIGCTRL_AUTOTXTEN_MASK
1038 #endif
1039 );
1040
1041 #if defined(USART_TRIGCTRL_AUTOTXTEN)
1042 if (init->autoTxTriggerEnable) {
1043 trigctrl |= USART_TRIGCTRL_AUTOTXTEN;
1044 }
1045 #endif
1046 if (init->txTriggerEnable) {
1047 trigctrl |= USART_TRIGCTRL_TXTEN;
1048 }
1049 if (init->rxTriggerEnable) {
1050 trigctrl |= USART_TRIGCTRL_RXTEN;
1051 }
1052 usart->TRIGCTRL = trigctrl;
1053 }
1054
1055 /***************************************************************************//**
1056 * @brief
1057 * Reset USART/UART to the same state that it was in after a hardware reset.
1058 *
1059 * @param[in] usart
1060 * A pointer to USART/UART peripheral register block.
1061 ******************************************************************************/
USART_Reset(USART_TypeDef * usart)1062 void USART_Reset(USART_TypeDef *usart)
1063 {
1064 /* Make sure the module exists on the selected chip. */
1065 EFM_ASSERT(USART_REF_VALID(usart)
1066 || USARTRF_REF_VALID(usart)
1067 || UART_REF_VALID(usart) );
1068
1069 #if defined(USART_EN_EN)
1070 usart->EN_SET = USART_EN_EN;
1071 /* Make sure disabled first, before resetting other registers. */
1072 usart->CMD = USART_CMD_RXDIS | USART_CMD_TXDIS | USART_CMD_MASTERDIS
1073 | USART_CMD_RXBLOCKDIS | USART_CMD_TXTRIDIS | USART_CMD_CLEARTX
1074 | USART_CMD_CLEARRX;
1075
1076 usart->CTRL = _USART_CTRL_RESETVALUE;
1077 usart->CTRLX = _USART_CTRLX_RESETVALUE;
1078 usart->FRAME = _USART_FRAME_RESETVALUE;
1079 usart->TRIGCTRL = _USART_TRIGCTRL_RESETVALUE;
1080 usart->CLKDIV = _USART_CLKDIV_RESETVALUE;
1081 usart->IEN = _USART_IEN_RESETVALUE;
1082 usart->IF_CLR = _USART_IF_MASK;
1083 usart->TIMING = _USART_TIMING_RESETVALUE;
1084
1085 if (USART_IRDA_VALID(usart)) {
1086 usart->IRCTRL = _USART_IRCTRL_RESETVALUE;
1087 }
1088
1089 if (USART_I2S_VALID(usart)) {
1090 usart->I2SCTRL = _USART_I2SCTRL_RESETVALUE;
1091 }
1092 usart->EN_CLR = USART_EN_EN;
1093
1094 #else
1095 /* Make sure disabled first, before resetting other registers */
1096 usart->CMD = USART_CMD_RXDIS | USART_CMD_TXDIS | USART_CMD_MASTERDIS
1097 | USART_CMD_RXBLOCKDIS | USART_CMD_TXTRIDIS | USART_CMD_CLEARTX
1098 | USART_CMD_CLEARRX;
1099
1100 usart->CTRL = _USART_CTRL_RESETVALUE;
1101 usart->FRAME = _USART_FRAME_RESETVALUE;
1102 usart->TRIGCTRL = _USART_TRIGCTRL_RESETVALUE;
1103 usart->CLKDIV = _USART_CLKDIV_RESETVALUE;
1104 usart->IEN = _USART_IEN_RESETVALUE;
1105 usart->IFC = _USART_IFC_MASK;
1106 #if defined(_USART_TIMING_MASK)
1107 usart->TIMING = _USART_TIMING_RESETVALUE;
1108 #endif
1109 #if defined(_USART_ROUTEPEN_MASK) || defined(_UART_ROUTEPEN_MASK)
1110 usart->ROUTEPEN = _USART_ROUTEPEN_RESETVALUE;
1111 usart->ROUTELOC0 = _USART_ROUTELOC0_RESETVALUE;
1112 usart->ROUTELOC1 = _USART_ROUTELOC1_RESETVALUE;
1113 #else
1114 usart->ROUTE = _USART_ROUTE_RESETVALUE;
1115 #endif
1116
1117 if (USART_IRDA_VALID(usart)) {
1118 usart->IRCTRL = _USART_IRCTRL_RESETVALUE;
1119 }
1120
1121 #if defined(_USART_INPUT_RESETVALUE)
1122 usart->INPUT = _USART_INPUT_RESETVALUE;
1123 #endif
1124
1125 #if defined(_USART_I2SCTRL_RESETVALUE)
1126 if (USART_I2S_VALID(usart)) {
1127 usart->I2SCTRL = _USART_I2SCTRL_RESETVALUE;
1128 }
1129 #endif
1130 #endif
1131 }
1132
1133 /***************************************************************************//**
1134 * @brief
1135 * Receive one 4-8 bit frame, (or part of 10-16 bit frame).
1136 *
1137 * @details
1138 * This function is normally used to receive one frame when operating with
1139 * frame length 4-8 bits. See @ref USART_RxExt() for reception of
1140 * 9 bit frames.
1141 *
1142 * Notice that possible parity/stop bits in asynchronous mode are not
1143 * considered part of a specified frame bit length.
1144 *
1145 * @note
1146 * This function will stall if the buffer is empty until data is received.
1147 * Alternatively, the user can explicitly check whether data is available.
1148 * If data is available, call @ref USART_RxDataGet() to read the RXDATA
1149 * register directly.
1150 *
1151 * @param[in] usart
1152 * A pointer to the USART/UART peripheral register block.
1153 *
1154 * @return
1155 * Data received.
1156 ******************************************************************************/
USART_Rx(USART_TypeDef * usart)1157 uint8_t USART_Rx(USART_TypeDef *usart)
1158 {
1159 while (!(usart->STATUS & USART_STATUS_RXDATAV)) {
1160 }
1161
1162 return (uint8_t)usart->RXDATA;
1163 }
1164
1165 /***************************************************************************//**
1166 * @brief
1167 * Receive two 4-8 bit frames or one 10-16 bit frame.
1168 *
1169 * @details
1170 * This function is normally used to receive one frame when operating with
1171 * frame length 10-16 bits. See @ref USART_RxDoubleExt() for
1172 * reception of two 9 bit frames.
1173 *
1174 * Notice that possible parity/stop bits in asynchronous mode are not
1175 * considered part of a specified frame bit length.
1176 *
1177 * @note
1178 * This function will stall if the buffer is empty until data is received.
1179 * Alternatively, the user can explicitly check whether data is available.
1180 * If data is available, call @ref USART_RxDoubleGet() to read the RXDOUBLE
1181 * register directly.
1182 *
1183 * @param[in] usart
1184 * A pointer to the USART/UART peripheral register block.
1185 *
1186 * @return
1187 * Data received.
1188 ******************************************************************************/
USART_RxDouble(USART_TypeDef * usart)1189 uint16_t USART_RxDouble(USART_TypeDef *usart)
1190 {
1191 while (!(usart->STATUS & USART_STATUS_RXFULL)) {
1192 }
1193
1194 return (uint16_t)usart->RXDOUBLE;
1195 }
1196
1197 /***************************************************************************//**
1198 * @brief
1199 * Receive two 4-9 bit frames, or one 10-16 bit frame with extended
1200 * information.
1201 *
1202 * @details
1203 * This function is normally used to receive one frame when operating with
1204 * frame length 10-16 bits and additional RX status information is required.
1205 *
1206 * Notice that possible parity/stop bits in asynchronous mode are not
1207 * considered part of a specified frame bit length.
1208 *
1209 * @note
1210 * This function will stall if buffer is empty until data is received.
1211 * Alternatively, the user can explicitly check whether data is available.
1212 * If data is available, call @ref USART_RxDoubleXGet() to read the RXDOUBLEX
1213 * register directly.
1214 *
1215 * @param[in] usart
1216 * A pointer to the USART/UART peripheral register block.
1217 *
1218 * @return
1219 * Data received.
1220 ******************************************************************************/
USART_RxDoubleExt(USART_TypeDef * usart)1221 uint32_t USART_RxDoubleExt(USART_TypeDef *usart)
1222 {
1223 while (!(usart->STATUS & USART_STATUS_RXFULL)) {
1224 }
1225
1226 return usart->RXDOUBLEX;
1227 }
1228
1229 /***************************************************************************//**
1230 * @brief
1231 * Receive one 4-9 bit frame (or part of 10-16 bit frame) with extended
1232 * information.
1233 *
1234 * @details
1235 * This function is normally used to receive one frame when operating with
1236 * frame length 4-9 bits and additional RX status information is required.
1237 *
1238 * Notice that possible parity/stop bits in asynchronous mode are not
1239 * considered part of a specified frame bit length.
1240 *
1241 * @note
1242 * This function will stall if the buffer is empty until data is received.
1243 * Alternatively, the user can explicitly check whether data is available.
1244 * If data is available, call @ref USART_RxDataXGet() to read the RXDATAX
1245 * register directly.
1246 *
1247 * @param[in] usart
1248 * A pointer to the USART/UART peripheral register block.
1249 *
1250 * @return
1251 * Data received.
1252 ******************************************************************************/
USART_RxExt(USART_TypeDef * usart)1253 uint16_t USART_RxExt(USART_TypeDef *usart)
1254 {
1255 while (!(usart->STATUS & USART_STATUS_RXDATAV)) {
1256 }
1257
1258 return (uint16_t)usart->RXDATAX;
1259 }
1260
1261 /***************************************************************************//**
1262 * @brief
1263 * Perform one 8 bit frame SPI transfer.
1264 *
1265 * @note
1266 * This function will stall if the transmit buffer is full. When a transmit
1267 * buffer becomes available, data is written and the function will wait until
1268 * data is fully transmitted. The SPI return value is then read out and
1269 * returned.
1270 *
1271 * @param[in] usart
1272 * A pointer to the USART peripheral register block.
1273 *
1274 * @param[in] data
1275 * Data to transmit.
1276 *
1277 * @return
1278 * Data received.
1279 ******************************************************************************/
USART_SpiTransfer(USART_TypeDef * usart,uint8_t data)1280 uint8_t USART_SpiTransfer(USART_TypeDef *usart, uint8_t data)
1281 {
1282 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1283 }
1284 usart->TXDATA = (uint32_t)data;
1285 while (!(usart->STATUS & USART_STATUS_TXC)) {
1286 }
1287 return (uint8_t)usart->RXDATA;
1288 }
1289
1290 /***************************************************************************//**
1291 * @brief
1292 * Transmit one 4-9 bit frame.
1293 *
1294 * @details
1295 * Depending on the frame length configuration, 4-8 (least significant) bits from
1296 * @p data are transmitted. If the frame length is 9, 8 bits are transmitted from
1297 * @p data and one bit as specified by CTRL register, BIT8DV field.
1298 * See USART_TxExt() for transmitting 9 bit frame with full control of
1299 * all 9 bits.
1300 *
1301 * Notice that possible parity/stop bits in asynchronous mode are not
1302 * considered part of a specified frame bit length.
1303 *
1304 * @note
1305 * This function will stall if the buffer is full until the buffer becomes available.
1306 *
1307 * @param[in] usart
1308 * A pointer to the USART/UART peripheral register block.
1309 *
1310 * @param[in] data
1311 * Data to transmit. See details above for more information.
1312 ******************************************************************************/
USART_Tx(USART_TypeDef * usart,uint8_t data)1313 void USART_Tx(USART_TypeDef *usart, uint8_t data)
1314 {
1315 /* Check that transmit buffer is empty */
1316 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1317 }
1318 usart->TXDATA = (uint32_t)data;
1319 }
1320
1321 /***************************************************************************//**
1322 * @brief
1323 * Transmit two 4-9 bit frames or one 10-16 bit frame.
1324 *
1325 * @details
1326 * Depending on the frame length configuration, 4-8 (least significant) bits from
1327 * each byte in @p data are transmitted. If frame length is 9, 8 bits are
1328 * transmitted from each byte in @p data adding one bit as specified by the CTRL
1329 * register, BIT8DV field, to each byte. See USART_TxDoubleExt()
1330 * for transmitting two 9 bit frames with full control of all 9 bits.
1331 *
1332 * If the frame length is 10-16, 10-16 (least significant) bits from @p data
1333 * are transmitted.
1334 *
1335 * Notice that possible parity/stop bits in asynchronous mode are not
1336 * considered part of a specified frame bit length.
1337 *
1338 * @note
1339 * This function will stall if the buffer is full until the buffer becomes available.
1340 *
1341 * @param[in] usart
1342 * A pointer to the USART/UART peripheral register block.
1343 *
1344 * @param[in] data
1345 * Data to transmit, the least significant byte holds the frame transmitted
1346 * first. See details above for more info.
1347 ******************************************************************************/
USART_TxDouble(USART_TypeDef * usart,uint16_t data)1348 void USART_TxDouble(USART_TypeDef *usart, uint16_t data)
1349 {
1350 /* Check that transmit buffer is empty */
1351 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1352 }
1353 usart->TXDOUBLE = (uint32_t)data;
1354 }
1355
1356 /***************************************************************************//**
1357 * @brief
1358 * Transmit two 4-9 bit frames or one 10-16 bit frame with extended control.
1359 *
1360 * @details
1361 * Notice that possible parity/stop bits in asynchronous mode are not
1362 * considered part of a specified frame bit length.
1363 *
1364 * @note
1365 * This function will stall if the buffer is full until the buffer becomes available.
1366 *
1367 * @param[in] usart
1368 * A pointer to the USART/UART peripheral register block.
1369 *
1370 * @param[in] data
1371 * Data to transmit with extended control. Contains two 16 bit words
1372 * concatenated. Least significant word holds the frame transmitted first. If the frame
1373 * length is 4-9, two frames with 4-9 least significant bits from each 16 bit
1374 * word are transmitted.
1375 * @par
1376 * If the frame length is 10-16 bits, 8 data bits are taken from the least
1377 * significant 16 bit word and the remaining bits from the other 16 bit word.
1378 * @par
1379 * Additional control bits are available as documented in the reference
1380 * manual (set to 0 if not used). For 10-16 bit frame length, these control
1381 * bits are taken from the most significant 16 bit word.
1382 ******************************************************************************/
USART_TxDoubleExt(USART_TypeDef * usart,uint32_t data)1383 void USART_TxDoubleExt(USART_TypeDef *usart, uint32_t data)
1384 {
1385 /* Check that transmit buffer is empty. */
1386 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1387 }
1388 usart->TXDOUBLEX = data;
1389 }
1390
1391 /***************************************************************************//**
1392 * @brief
1393 * Transmit one 4-9 bit frame with extended control.
1394 *
1395 * @details
1396 * Notice that possible parity/stop bits in asynchronous mode are not
1397 * considered part of a specified frame bit length.
1398 *
1399 * @note
1400 * This function will stall if the buffer is full until the buffer becomes available.
1401 *
1402 * @param[in] usart
1403 * A pointer to the USART/UART peripheral register block.
1404 *
1405 * @param[in] data
1406 * Data to transmit with extended control. Least significant bit contains
1407 * frame bits. Additional control bits are available as documented in
1408 * the reference manual (set to 0 if not used).
1409 ******************************************************************************/
USART_TxExt(USART_TypeDef * usart,uint16_t data)1410 void USART_TxExt(USART_TypeDef *usart, uint16_t data)
1411 {
1412 /* Check that the transmit buffer is empty. */
1413 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1414 }
1415 usart->TXDATAX = (uint32_t)data;
1416 }
1417
1418 /** @} (end addtogroup usart) */
1419 #endif /* defined(USART_COUNT) && (USART_COUNT > 0) */
1420