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 "sl_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 defined(UART_COUNT) && (UART_COUNT == 1) && !defined(_UART_IPVERSION_MASK)
143 #define UART_REF_VALID(ref) ((ref) == UART0)
144 #elif defined(UART_COUNT) && (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 = 0;
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 break;
395 }
396
397 if (oversample > 0U) {
398 /* Calculate and set CLKDIV with fractional bits.
399 * The added (oversample*baudrate)/2 in the first line is to round the
400 * divisor to the nearest fractional divisor. */
401 #if defined(_SILICON_LABS_32B_SERIES_0) && !defined(_EFM32_HAPPY_FAMILY)
402 /* Devices with 2 fractional bits. CLKDIV[7:6] */
403 clkdiv = 4 * refFreq + (oversample * baudrate) / 2;
404 clkdiv /= oversample * baudrate;
405 clkdiv -= 4;
406 clkdiv *= 64;
407 #else
408 /* Devices with 5 fractional bits. CLKDIV[7:3] */
409 clkdiv = 32 * refFreq + (oversample * baudrate) / 2;
410 clkdiv /= oversample * baudrate;
411 clkdiv -= 32;
412 clkdiv *= 8;
413 #endif
414
415 /* Verify that the resulting clock divider is within limits. */
416 EFM_ASSERT(clkdiv <= CLKDIV_MASK);
417
418 /* Make sure that reserved bits are not written to. */
419 clkdiv &= CLKDIV_MASK;
420
421 usart->CTRL &= ~_USART_CTRL_OVS_MASK;
422 usart->CTRL |= ovs;
423 usart->CLKDIV = clkdiv;
424 }
425 }
426
427 /***************************************************************************//**
428 * @brief
429 * Calculate baudrate for USART/UART given reference frequency, clock division,
430 * and oversampling rate (if async mode).
431 *
432 * @details
433 * This function returns the baudrate that a USART/UART module will use if
434 * configured with the given frequency, clock divisor, and mode. Notice that
435 * this function will not use the hardware configuration. It can be used
436 * to determine if a given configuration is sufficiently accurate for the
437 * application.
438 *
439 * @param[in] refFreq
440 * USART/UART HF peripheral frequency used.
441 *
442 * @param[in] clkdiv
443 * A clock division factor to be used.
444 *
445 * @param[in] syncmode
446 * @li True - synchronous mode operation.
447 * @li False - asynchronous mode operation.
448 *
449 * @param[in] ovs
450 * Oversampling used if in asynchronous mode. Not used if @p syncmode is true.
451 *
452 * @return
453 * Baudrate with given settings.
454 ******************************************************************************/
USART_BaudrateCalc(uint32_t refFreq,uint32_t clkdiv,bool syncmode,USART_OVS_TypeDef ovs)455 uint32_t USART_BaudrateCalc(uint32_t refFreq,
456 uint32_t clkdiv,
457 bool syncmode,
458 USART_OVS_TypeDef ovs)
459 {
460 uint32_t oversample;
461 uint64_t divisor;
462 uint64_t factor;
463 uint64_t remainder;
464 uint64_t quotient;
465 uint32_t br;
466
467 /* Out of bound clkdiv. */
468 EFM_ASSERT(clkdiv <= CLKDIV_MASK);
469
470 /* Mask out unused bits */
471 clkdiv &= CLKDIV_MASK;
472
473 /* Use integer division to avoid forcing in float division */
474 /* utils and yet keep rounding effect errors to a minimum. */
475
476 /* Baudrate calculation depends on if synchronous or asynchronous mode. */
477 if (syncmode) {
478 /*
479 * Baudrate is given by:
480 *
481 * br = fHFPERCLK/(2 * (1 + (CLKDIV / 256)))
482 *
483 * which can be rewritten to
484 *
485 * br = (128 * fHFPERCLK)/(256 + CLKDIV)
486 */
487 oversample = 1; /* Not used in sync mode, i.e., 1 */
488 factor = 128;
489 } else {
490 /*
491 * Baudrate in asynchronous mode is given by:
492 *
493 * br = fHFPERCLK/(oversample * (1 + (CLKDIV / 256)))
494 *
495 * which can be rewritten to
496 *
497 * br = (256 * fHFPERCLK)/(oversample * (256 + CLKDIV))
498 *
499 * 256 factor of the dividend is reduced with a
500 * (part of) oversample part of the divisor.
501 */
502
503 switch (ovs) {
504 case usartOVS16:
505 oversample = 1;
506 factor = 256 / 16;
507 break;
508
509 case usartOVS8:
510 oversample = 1;
511 factor = 256 / 8;
512 break;
513
514 case usartOVS6:
515 oversample = 3;
516 factor = 256 / 2;
517 break;
518
519 default:
520 oversample = 1;
521 factor = 256 / 4;
522 break;
523 }
524 }
525
526 /*
527 * The basic problem with integer division in the above formula is that
528 * the dividend (factor * fHFPERCLK) may become larger than a 32 bit
529 * integer. Yet we want to evaluate the dividend first before dividing
530 * to get as small rounding effects as possible. Too harsh restrictions
531 * should not be made on the maximum fHFPERCLK value either.
532 *
533 * For division a/b,
534 *
535 * a = qb + r
536 *
537 * where q is the quotient and r is the remainder, both integers.
538 *
539 * The original baudrate formula can be rewritten as
540 *
541 * br = xa / b = x(qb + r)/b = xq + xr/b
542 *
543 * where x is 'factor', a is 'refFreq' and b is 'divisor', referring to
544 * variable names.
545 */
546
547 /*
548 * The divisor will never exceed max 32 bit value since
549 * clkdiv <= _USART_CLKDIV_DIV_MASK (currently 0x1FFFC0 or 0x7FFFF8)
550 * and 'oversample' has been reduced to <= 3.
551 */
552 divisor = (uint64_t)(oversample * (256 + clkdiv));
553
554 quotient = refFreq / divisor;
555 remainder = refFreq % divisor;
556
557 /* The factor <= 128 and since divisor >= 256, the below cannot exceed the maximum */
558 /* 32 bit value. However, factor * remainder can become larger than 32-bit */
559 /* because of the size of _USART_CLKDIV_DIV_MASK on some families. */
560 br = (uint32_t)(factor * quotient);
561
562 /*
563 * The factor <= 128 and remainder < (oversample*(256 + clkdiv)), which
564 * means dividend (factor * remainder) worst case is
565 * 128 * (3 * (256 + _USART_CLKDIV_DIV_MASK)) = 0x1_8001_7400.
566 */
567 br += (uint32_t)((factor * remainder) / divisor);
568
569 return br;
570 }
571
572 /***************************************************************************//**
573 * @brief
574 * Get the current baudrate for USART/UART.
575 *
576 * @details
577 * This function returns the actual baudrate (not considering oscillator
578 * inaccuracies) used by a USART/UART peripheral.
579 *
580 * @param[in] usart
581 * A pointer to the USART/UART peripheral register block.
582 *
583 * @return
584 * The current baudrate.
585 ******************************************************************************/
USART_BaudrateGet(USART_TypeDef * usart)586 uint32_t USART_BaudrateGet(USART_TypeDef *usart)
587 {
588 uint32_t freq;
589 USART_OVS_TypeDef ovs;
590 bool syncmode;
591
592 if (usart->CTRL & USART_CTRL_SYNC) {
593 syncmode = true;
594 } else {
595 syncmode = false;
596 }
597
598 /* HFPERCLK/HFPERBCLK used to clock all USART/UART peripheral modules. */
599 #if defined(_SILICON_LABS_32B_SERIES_2)
600 freq = CMU_ClockFreqGet(cmuClock_PCLK);
601 #else
602 #if defined(_CMU_HFPERPRESCB_MASK)
603 if (usart == USART2) {
604 freq = CMU_ClockFreqGet(cmuClock_HFPERB);
605 } else {
606 freq = CMU_ClockFreqGet(cmuClock_HFPER);
607 }
608 #else
609 freq = CMU_ClockFreqGet(cmuClock_HFPER);
610 #endif
611 #endif
612 ovs = (USART_OVS_TypeDef)(usart->CTRL & _USART_CTRL_OVS_MASK);
613 return USART_BaudrateCalc(freq, usart->CLKDIV, syncmode, ovs);
614 }
615
616 /***************************************************************************//**
617 * @brief
618 * Configure the USART operating in synchronous mode to use a given baudrate
619 * (or as close as possible to a specified baudrate).
620 *
621 * @details
622 * The configuration will be set to use a baudrate <= the specified baudrate
623 * to ensure that the baudrate does not exceed the specified value.
624 *
625 * The fractional clock division is suppressed, although the hardware design allows it.
626 * It could cause half clock cycles to exceed a specified limit and thus
627 * potentially violate specifications for the slave device. In some special
628 * situations, a fractional clock division may be useful even in synchronous
629 * mode, but in those cases it must be directly adjusted, possibly assisted
630 * by USART_BaudrateCalc():
631 *
632 * @warning
633 * The consequence of the aforementioned suppression of the fractional part of
634 * the clock divider is that some frequencies won't be achievable. The divider
635 * will only be able to be an integer value so the reference clock will only be
636 * dividable by N (where N is a positive integer).
637 *
638 * @param[in] usart
639 * A pointer to the USART peripheral register block. (Cannot be used on UART
640 * modules.)
641 *
642 * @param[in] refFreq
643 * A USART reference clock frequency in Hz that will be used. If set to 0,
644 * the currently-configured reference clock is assumed.
645 *
646 * @param[in] baudrate
647 * Baudrate to try to achieve for USART.
648 ******************************************************************************/
USART_BaudrateSyncSet(USART_TypeDef * usart,uint32_t refFreq,uint32_t baudrate)649 void USART_BaudrateSyncSet(USART_TypeDef *usart, uint32_t refFreq, uint32_t baudrate)
650 {
651 uint32_t clkdiv;
652
653 /* Prevent dividing by 0. */
654 EFM_ASSERT(baudrate);
655
656 /*
657 * CLKDIV in synchronous mode is given by:
658 *
659 * CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1)
660 */
661
662 /* HFPERCLK/HFPERBCLK used to clock all USART/UART peripheral modules. */
663 if (!refFreq) {
664 #if defined(_SILICON_LABS_32B_SERIES_2)
665 refFreq = CMU_ClockFreqGet(cmuClock_PCLK);
666 #else
667 #if defined(_CMU_HFPERPRESCB_MASK)
668 if (usart == USART2) {
669 refFreq = CMU_ClockFreqGet(cmuClock_HFPERB);
670 } else {
671 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
672 }
673 #else
674 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
675 #endif
676 #endif
677 }
678
679 /*
680 * The clock divider computation is done by using unsigned integer.
681 * The goal is to truncate the fractional part of the resulting
682 * clock divider value.
683 * Note: The divider field of the USART->CLKDIV register is of the following form:
684 * xxxxxxxxxxxxxxx.yyyyy where x is the 15 bits integral part of the divider
685 * and y is the 5 bits fractional part.
686 */
687 clkdiv = (refFreq - 1) / (2 * baudrate);
688 clkdiv = clkdiv << 8;
689
690 /* Verify that resulting clock divider is within limits. */
691 EFM_ASSERT(!(clkdiv & ~CLKDIV_MASK));
692
693 usart->CLKDIV = clkdiv;
694 }
695
696 /***************************************************************************//**
697 * @brief
698 * Enable/disable USART/UART receiver and/or transmitter.
699 *
700 * @details
701 * Notice that this function does not do any configuration. Enabling should
702 * normally be done after initialization (if not enabled as part
703 * of initialization).
704 *
705 * @param[in] usart
706 * A pointer to the USART/UART peripheral register block.
707 *
708 * @param[in] enable
709 * Select the status for the receiver/transmitter.
710 ******************************************************************************/
USART_Enable(USART_TypeDef * usart,USART_Enable_TypeDef enable)711 void USART_Enable(USART_TypeDef *usart, USART_Enable_TypeDef enable)
712 {
713 uint32_t tmp;
714
715 /* Make sure the module exists on the selected chip. */
716 EFM_ASSERT(USART_REF_VALID(usart)
717 || USARTRF_REF_VALID(usart)
718 || UART_REF_VALID(usart));
719
720 #if defined(USART_EN_EN)
721 usart->EN_SET = USART_EN_EN;
722 #endif
723
724 /* Disable as specified. */
725 tmp = ~((uint32_t)enable);
726 tmp &= _USART_CMD_RXEN_MASK | _USART_CMD_TXEN_MASK;
727 usart->CMD = tmp << 1;
728
729 /* Enable as specified. */
730 usart->CMD = (uint32_t)enable;
731
732 #if defined(USART_EN_EN)
733 if (enable == usartDisable) {
734 usart->EN_CLR = USART_EN_EN;
735 }
736 #endif
737 }
738
739 /***************************************************************************//**
740 * @brief
741 * Initialize USART/UART for normal asynchronous mode.
742 *
743 * @details
744 * This function will configure basic settings to operate in normal
745 * asynchronous mode.
746 *
747 * A special control setup not covered by this function must be done after
748 * using this function by direct modification of the CTRL register.
749 *
750 * Notice that pins used by the USART/UART module must be properly configured
751 * by the user explicitly for the USART/UART to work as intended.
752 * (When configuring pins, remember to consider the sequence of
753 * configuration to avoid unintended pulses/glitches on output
754 * pins.)
755 *
756 * @param[in] usart
757 * A pointer to the USART/UART peripheral register block.
758 *
759 * @param[in] init
760 * A pointer to the initialization structure used to configure the basic async setup.
761 ******************************************************************************/
USART_InitAsync(USART_TypeDef * usart,const USART_InitAsync_TypeDef * init)762 void USART_InitAsync(USART_TypeDef *usart, const USART_InitAsync_TypeDef *init)
763 {
764 /* Make sure the module exists on the selected chip. */
765 EFM_ASSERT(USART_REF_VALID(usart)
766 || USARTRF_REF_VALID(usart)
767 || UART_REF_VALID(usart));
768
769 /* Initialize USART registers to hardware reset state. */
770 USART_Reset(usart);
771
772 #if defined(USART_EN_EN)
773 usart->EN_SET = USART_EN_EN;
774 #endif
775
776 #if defined(USART_CTRL_MVDIS)
777 /* Disable the majority vote if specified. */
778 if (init->mvdis) {
779 usart->CTRL |= USART_CTRL_MVDIS;
780 }
781 #endif
782
783 #if !defined(_EFM32_GECKO_FAMILY)
784 /* Configure the PRS input mode. */
785 if (init->prsRxEnable) {
786 prsRxInput(usart, init->prsRxCh);
787 }
788 #endif
789
790 /* Configure databits, stopbits, and parity. */
791 usart->FRAME = (uint32_t)init->databits
792 | (uint32_t)init->stopbits
793 | (uint32_t)init->parity;
794
795 /* Configure baudrate. */
796 USART_BaudrateAsyncSet(usart, init->refFreq, init->baudrate, init->oversampling);
797
798 if (init->autoCsEnable) {
799 usart->CTRL |= USART_CTRL_AUTOCS;
800 }
801 if (init->csInv) {
802 usart->CTRL |= USART_CTRL_CSINV;
803 }
804 #if defined(_USART_TIMING_CSHOLD_MASK)
805 usart->TIMING = (((uint32_t)init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
806 & _USART_TIMING_CSHOLD_MASK)
807 | (((uint32_t)init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
808 & _USART_TIMING_CSSETUP_MASK);
809
810 #endif
811
812 #if defined(_USART_ROUTEPEN_RTSPEN_MASK) && defined(_USART_ROUTEPEN_CTSPEN_MASK)
813 usart->ROUTEPEN &= ~(_USART_ROUTEPEN_RTSPEN_MASK | _USART_ROUTEPEN_CTSPEN_MASK);
814 usart->ROUTEPEN |= init->hwFlowControl;
815
816 #elif defined(USART_CTRLX_CTSEN)
817 if ((init->hwFlowControl == usartHwFlowControlRts)
818 || (init->hwFlowControl == usartHwFlowControlCtsAndRts)) {
819 #if USART_COUNT > 1
820 GPIO->USARTROUTE_SET[USART_NUM(usart)].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
821 #else
822 //! @todo cleanup when ADM is updated to have USART_NUM macros
823 GPIO->USARTROUTE_SET[0].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
824 #endif
825 } else {
826 #if USART_COUNT > 1
827 GPIO->USARTROUTE_CLR[USART_NUM(usart)].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
828 #else
829 //! @todo cleanup when ADM is updated to have USART_NUM macros
830 GPIO->USARTROUTE_CLR[0].ROUTEEN = GPIO_USART_ROUTEEN_RTSPEN;
831 #endif
832 }
833
834 if ((init->hwFlowControl == usartHwFlowControlCts)
835 || (init->hwFlowControl == usartHwFlowControlCtsAndRts)) {
836 usart->CTRLX_SET = USART_CTRLX_CTSEN;
837 } else {
838 usart->CTRLX_CLR = USART_CTRLX_CTSEN;
839 }
840 #endif
841
842 /* Finally, enable (as specified). */
843 usart->CMD = (uint32_t)init->enable;
844 }
845
846 /***************************************************************************//**
847 * @brief
848 * Initialize USART for synchronous mode.
849 *
850 * @details
851 * This function will configure basic settings to operate in
852 * synchronous mode.
853 *
854 * A special control setup not covered by this function must be done after
855 * using this function by direct modification of the CTRL register.
856 *
857 * Notice that pins used by the USART module must be properly configured
858 * by the user explicitly for the USART to work as intended.
859 * (When configuring pins remember to consider the sequence of
860 * configuration to avoid unintended pulses/glitches on output
861 * pins.)
862 *
863 * @param[in] usart
864 * A pointer to the USART peripheral register block. (UART does not support this
865 * mode.)
866 *
867 * @param[in] init
868 * A pointer to the initialization structure used to configure basic async setup.
869 ******************************************************************************/
USART_InitSync(USART_TypeDef * usart,const USART_InitSync_TypeDef * init)870 void USART_InitSync(USART_TypeDef *usart, const USART_InitSync_TypeDef *init)
871 {
872 /* Make sure the module exists on the selected chip. */
873 EFM_ASSERT(USART_REF_VALID(usart) || USARTRF_REF_VALID(usart) );
874
875 /* Initialize USART registers to hardware reset state. */
876 USART_Reset(usart);
877
878 #if defined(USART_EN_EN)
879 usart->EN_SET = USART_EN_EN;
880 #endif
881
882 /* Set bits for synchronous mode. */
883 usart->CTRL |= (USART_CTRL_SYNC)
884 | (uint32_t)init->clockMode
885 | (init->msbf ? USART_CTRL_MSBF : 0);
886
887 #if defined(_USART_CTRL_AUTOTX_MASK)
888 usart->CTRL |= init->autoTx ? USART_CTRL_AUTOTX : 0;
889 #endif
890
891 #if !defined(_EFM32_GECKO_FAMILY)
892 if (init->prsRxEnable) {
893 prsRxInput(usart, init->prsRxCh);
894 }
895 #endif
896
897 /* Configure databits, leave stopbits and parity at reset default (not used). */
898 usart->FRAME = (uint32_t)init->databits
899 | USART_FRAME_STOPBITS_DEFAULT
900 | USART_FRAME_PARITY_DEFAULT;
901
902 /* Configure the baudrate. */
903 USART_BaudrateSyncSet(usart, init->refFreq, init->baudrate);
904
905 /* Finally, enable (as specified). */
906 if (init->master) {
907 usart->CMD = USART_CMD_MASTEREN;
908 }
909
910 if (init->autoCsEnable) {
911 usart->CTRL |= USART_CTRL_AUTOCS;
912 }
913 if (init->csInv) {
914 usart->CTRL |= USART_CTRL_CSINV;
915 }
916 #if defined(_USART_TIMING_CSHOLD_MASK)
917 usart->TIMING = (((uint32_t)init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
918 & _USART_TIMING_CSHOLD_MASK)
919 | (((uint32_t)init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
920 & _USART_TIMING_CSSETUP_MASK);
921 #endif
922
923 usart->CMD = (uint32_t)init->enable;
924 }
925
926 /***************************************************************************//**
927 * @brief
928 * Initialize USART for asynchronous IrDA mode.
929 *
930 * @details
931 * This function will configure basic settings to operate in
932 * asynchronous IrDA mode.
933 *
934 * A special control setup not covered by this function must be done after
935 * using this function by direct modification of the CTRL and IRCTRL
936 * registers.
937 *
938 * Notice that pins used by the USART/UART module must be properly configured
939 * by the user explicitly for the USART/UART to work as intended.
940 * (When configuring pins, remember to consider the sequence of
941 * configuration to avoid unintended pulses/glitches on output
942 * pins.)
943 *
944 * @param[in] usart
945 * A pointer to the USART peripheral register block.
946 *
947 * @param[in] init
948 * A pointer to the initialization structure used to configure async IrDA setup.
949 *
950 * @note
951 * Not all USART instances support IrDA. See the data sheet for your device.
952 *
953 ******************************************************************************/
USARTn_InitIrDA(USART_TypeDef * usart,const USART_InitIrDA_TypeDef * init)954 void USARTn_InitIrDA(USART_TypeDef *usart, const USART_InitIrDA_TypeDef *init)
955 {
956 EFM_ASSERT(USART_IRDA_VALID(usart));
957
958 /* Initialize USART as an async device. */
959 USART_InitAsync(usart, &(init->async));
960
961 /* Set IrDA modulation to RZI (return-to-zero-inverted). */
962 usart->CTRL |= USART_CTRL_TXINV;
963
964 /* Invert the Rx signal before the demodulator if enabled. */
965 if (init->irRxInv) {
966 usart->CTRL |= USART_CTRL_RXINV;
967 }
968
969 /* Configure IrDA. */
970 usart->IRCTRL = (uint32_t)init->irPw
971 | ((init->irFilt ? 1UL : 0UL) << _USART_IRCTRL_IRFILT_SHIFT);
972
973 #if defined(USART_IRCTRL_IRPRSEN)
974 if (init->irPrsEn) {
975 prsIrInput(usart, init->irPrsSel);
976 }
977 #endif
978
979 /* Enable IrDA. */
980 usart->IRCTRL |= USART_IRCTRL_IREN;
981 }
982
983 #if defined(_USART_I2SCTRL_MASK)
984 /***************************************************************************//**
985 * @brief
986 * Initialize USART for I2S mode.
987 *
988 * @details
989 * This function will configure basic settings to operate in I2S
990 * mode.
991 *
992 * A special control setup not covered by this function must be done after
993 * using this function by direct modification of the CTRL and I2SCTRL
994 * registers.
995 *
996 * Notice that pins used by the USART module must be properly configured
997 * by the user explicitly for the USART to work as intended.
998 * (When configuring pins, remember to consider the sequence of
999 * configuration to avoid unintended pulses/glitches on output
1000 * pins.)
1001 *
1002 * @param[in] usart
1003 * A pointer to the USART peripheral register block. (UART does not support this
1004 * mode.)
1005 *
1006 * @param[in] init
1007 * A pointer to the initialization structure used to configure the basic I2S setup.
1008 *
1009 * @note
1010 * This function does not apply to all USART's. See the chip Reference Manual.
1011 *
1012 ******************************************************************************/
USART_InitI2s(USART_TypeDef * usart,USART_InitI2s_TypeDef * init)1013 void USART_InitI2s(USART_TypeDef *usart, USART_InitI2s_TypeDef *init)
1014 {
1015 USART_Enable_TypeDef enable;
1016
1017 /* Make sure the module exists on the selected chip. */
1018 EFM_ASSERT(USART_I2S_VALID(usart));
1019
1020 /* Override the enable setting. */
1021 enable = init->sync.enable;
1022 init->sync.enable = usartDisable;
1023
1024 /* Initialize USART as a sync device. */
1025 USART_InitSync(usart, &init->sync);
1026
1027 /* Configure and enable I2CCTRL register according to the selected mode. */
1028 usart->I2SCTRL = (uint32_t)init->format
1029 | (uint32_t)init->justify
1030 | (init->delay ? USART_I2SCTRL_DELAY : 0)
1031 | (init->dmaSplit ? USART_I2SCTRL_DMASPLIT : 0)
1032 | (init->mono ? USART_I2SCTRL_MONO : 0)
1033 | USART_I2SCTRL_EN;
1034
1035 if (enable != usartDisable) {
1036 USART_Enable(usart, enable);
1037 }
1038 }
1039 #endif
1040
1041 /***************************************************************************//**
1042 * @brief
1043 * Initialize the automatic transmissions using PRS channel as a trigger.
1044 * @note
1045 * Initialize USART with USART_Init() before setting up the PRS configuration.
1046 *
1047 * @param[in] usart
1048 * A pointer to USART to configure.
1049 *
1050 * @param[in] init
1051 * A pointer to the initialization structure.
1052 ******************************************************************************/
USART_InitPrsTrigger(USART_TypeDef * usart,const USART_PrsTriggerInit_TypeDef * init)1053 void USART_InitPrsTrigger(USART_TypeDef *usart, const USART_PrsTriggerInit_TypeDef *init)
1054 {
1055 uint32_t trigctrl;
1056
1057 prsTriggerInput(usart, init->prsTriggerChannel);
1058 /* Clear values that will be reconfigured. */
1059 trigctrl = usart->TRIGCTRL & ~(_USART_TRIGCTRL_RXTEN_MASK
1060 | _USART_TRIGCTRL_TXTEN_MASK
1061 #if defined(USART_TRIGCTRL_AUTOTXTEN)
1062 | _USART_TRIGCTRL_AUTOTXTEN_MASK
1063 #endif
1064 );
1065
1066 #if defined(USART_TRIGCTRL_AUTOTXTEN)
1067 if (init->autoTxTriggerEnable) {
1068 trigctrl |= USART_TRIGCTRL_AUTOTXTEN;
1069 }
1070 #endif
1071 if (init->txTriggerEnable) {
1072 trigctrl |= USART_TRIGCTRL_TXTEN;
1073 }
1074 if (init->rxTriggerEnable) {
1075 trigctrl |= USART_TRIGCTRL_RXTEN;
1076 }
1077 usart->TRIGCTRL = trigctrl;
1078 }
1079
1080 /***************************************************************************//**
1081 * @brief
1082 * Reset USART/UART to the same state that it was in after a hardware reset.
1083 *
1084 * @param[in] usart
1085 * A pointer to USART/UART peripheral register block.
1086 ******************************************************************************/
USART_Reset(USART_TypeDef * usart)1087 void USART_Reset(USART_TypeDef *usart)
1088 {
1089 /* Make sure the module exists on the selected chip. */
1090 EFM_ASSERT(USART_REF_VALID(usart)
1091 || USARTRF_REF_VALID(usart)
1092 || UART_REF_VALID(usart) );
1093
1094 #if defined(USART_EN_EN)
1095 usart->EN_SET = USART_EN_EN;
1096 /* Make sure disabled first, before resetting other registers. */
1097 usart->CMD = USART_CMD_RXDIS | USART_CMD_TXDIS | USART_CMD_MASTERDIS
1098 | USART_CMD_RXBLOCKDIS | USART_CMD_TXTRIDIS | USART_CMD_CLEARTX
1099 | USART_CMD_CLEARRX;
1100
1101 usart->CTRL = _USART_CTRL_RESETVALUE;
1102 usart->CTRLX = _USART_CTRLX_RESETVALUE;
1103 usart->FRAME = _USART_FRAME_RESETVALUE;
1104 usart->TRIGCTRL = _USART_TRIGCTRL_RESETVALUE;
1105 usart->CLKDIV = _USART_CLKDIV_RESETVALUE;
1106 usart->IEN = _USART_IEN_RESETVALUE;
1107 usart->IF_CLR = _USART_IF_MASK;
1108 usart->TIMING = _USART_TIMING_RESETVALUE;
1109
1110 if (USART_IRDA_VALID(usart)) {
1111 usart->IRCTRL = _USART_IRCTRL_RESETVALUE;
1112 }
1113
1114 if (USART_I2S_VALID(usart)) {
1115 usart->I2SCTRL = _USART_I2SCTRL_RESETVALUE;
1116 }
1117 usart->EN_CLR = USART_EN_EN;
1118
1119 #else
1120 /* Make sure disabled first, before resetting other registers */
1121 usart->CMD = USART_CMD_RXDIS | USART_CMD_TXDIS | USART_CMD_MASTERDIS
1122 | USART_CMD_RXBLOCKDIS | USART_CMD_TXTRIDIS | USART_CMD_CLEARTX
1123 | USART_CMD_CLEARRX;
1124
1125 usart->CTRL = _USART_CTRL_RESETVALUE;
1126 usart->FRAME = _USART_FRAME_RESETVALUE;
1127 usart->TRIGCTRL = _USART_TRIGCTRL_RESETVALUE;
1128 usart->CLKDIV = _USART_CLKDIV_RESETVALUE;
1129 usart->IEN = _USART_IEN_RESETVALUE;
1130 usart->IFC = _USART_IFC_MASK;
1131 #if defined(_USART_TIMING_MASK)
1132 usart->TIMING = _USART_TIMING_RESETVALUE;
1133 #endif
1134 #if defined(_USART_ROUTEPEN_MASK) || defined(_UART_ROUTEPEN_MASK)
1135 usart->ROUTEPEN = _USART_ROUTEPEN_RESETVALUE;
1136 usart->ROUTELOC0 = _USART_ROUTELOC0_RESETVALUE;
1137 usart->ROUTELOC1 = _USART_ROUTELOC1_RESETVALUE;
1138 #else
1139 usart->ROUTE = _USART_ROUTE_RESETVALUE;
1140 #endif
1141
1142 if (USART_IRDA_VALID(usart)) {
1143 usart->IRCTRL = _USART_IRCTRL_RESETVALUE;
1144 }
1145
1146 #if defined(_USART_INPUT_RESETVALUE)
1147 usart->INPUT = _USART_INPUT_RESETVALUE;
1148 #endif
1149
1150 #if defined(_USART_I2SCTRL_RESETVALUE)
1151 if (USART_I2S_VALID(usart)) {
1152 usart->I2SCTRL = _USART_I2SCTRL_RESETVALUE;
1153 }
1154 #endif
1155 #endif
1156 }
1157
1158 /***************************************************************************//**
1159 * @brief
1160 * Receive one 4-8 bit frame, (or part of 10-16 bit frame).
1161 *
1162 * @details
1163 * This function is normally used to receive one frame when operating with
1164 * frame length 4-8 bits. See @ref USART_RxExt() for reception of
1165 * 9 bit frames.
1166 *
1167 * Notice that possible parity/stop bits in asynchronous mode are not
1168 * considered part of a specified frame bit length.
1169 *
1170 * @note
1171 * This function will stall if the buffer is empty until data is received.
1172 * Alternatively, the user can explicitly check whether data is available.
1173 * If data is available, call @ref USART_RxDataGet() to read the RXDATA
1174 * register directly.
1175 *
1176 * @param[in] usart
1177 * A pointer to the USART/UART peripheral register block.
1178 *
1179 * @return
1180 * Data received.
1181 ******************************************************************************/
USART_Rx(USART_TypeDef * usart)1182 uint8_t USART_Rx(USART_TypeDef *usart)
1183 {
1184 while (!(usart->STATUS & USART_STATUS_RXDATAV)) {
1185 }
1186
1187 return (uint8_t)usart->RXDATA;
1188 }
1189
1190 /***************************************************************************//**
1191 * @brief
1192 * Receive two 4-8 bit frames or one 10-16 bit frame.
1193 *
1194 * @details
1195 * This function is normally used to receive one frame when operating with
1196 * frame length 10-16 bits. See @ref USART_RxDoubleExt() for
1197 * reception of two 9 bit frames.
1198 *
1199 * Notice that possible parity/stop bits in asynchronous mode are not
1200 * considered part of a specified frame bit length.
1201 *
1202 * @note
1203 * This function will stall if the buffer is empty until data is received.
1204 * Alternatively, the user can explicitly check whether data is available.
1205 * If data is available, call @ref USART_RxDoubleGet() to read the RXDOUBLE
1206 * register directly.
1207 *
1208 * @param[in] usart
1209 * A pointer to the USART/UART peripheral register block.
1210 *
1211 * @return
1212 * Data received.
1213 ******************************************************************************/
USART_RxDouble(USART_TypeDef * usart)1214 uint16_t USART_RxDouble(USART_TypeDef *usart)
1215 {
1216 while (!(usart->STATUS & USART_STATUS_RXFULL)) {
1217 }
1218
1219 return (uint16_t)usart->RXDOUBLE;
1220 }
1221
1222 /***************************************************************************//**
1223 * @brief
1224 * Receive two 4-9 bit frames, or one 10-16 bit frame with extended
1225 * information.
1226 *
1227 * @details
1228 * This function is normally used to receive one frame when operating with
1229 * frame length 10-16 bits and additional RX status information is required.
1230 *
1231 * Notice that possible parity/stop bits in asynchronous mode are not
1232 * considered part of a specified frame bit length.
1233 *
1234 * @note
1235 * This function will stall if buffer is empty until data is received.
1236 * Alternatively, the user can explicitly check whether data is available.
1237 * If data is available, call @ref USART_RxDoubleXGet() to read the RXDOUBLEX
1238 * register directly.
1239 *
1240 * @param[in] usart
1241 * A pointer to the USART/UART peripheral register block.
1242 *
1243 * @return
1244 * Data received.
1245 ******************************************************************************/
USART_RxDoubleExt(USART_TypeDef * usart)1246 uint32_t USART_RxDoubleExt(USART_TypeDef *usart)
1247 {
1248 while (!(usart->STATUS & USART_STATUS_RXFULL)) {
1249 }
1250
1251 return usart->RXDOUBLEX;
1252 }
1253
1254 /***************************************************************************//**
1255 * @brief
1256 * Receive one 4-9 bit frame (or part of 10-16 bit frame) with extended
1257 * information.
1258 *
1259 * @details
1260 * This function is normally used to receive one frame when operating with
1261 * frame length 4-9 bits and additional RX status information is required.
1262 *
1263 * Notice that possible parity/stop bits in asynchronous mode are not
1264 * considered part of a specified frame bit length.
1265 *
1266 * @note
1267 * This function will stall if the buffer is empty until data is received.
1268 * Alternatively, the user can explicitly check whether data is available.
1269 * If data is available, call @ref USART_RxDataXGet() to read the RXDATAX
1270 * register directly.
1271 *
1272 * @param[in] usart
1273 * A pointer to the USART/UART peripheral register block.
1274 *
1275 * @return
1276 * Data received.
1277 ******************************************************************************/
USART_RxExt(USART_TypeDef * usart)1278 uint16_t USART_RxExt(USART_TypeDef *usart)
1279 {
1280 while (!(usart->STATUS & USART_STATUS_RXDATAV)) {
1281 }
1282
1283 return (uint16_t)usart->RXDATAX;
1284 }
1285
1286 /***************************************************************************//**
1287 * @brief
1288 * Perform one 8 bit frame SPI transfer.
1289 *
1290 * @note
1291 * This function will stall if the transmit buffer is full. When a transmit
1292 * buffer becomes available, data is written and the function will wait until
1293 * data is fully transmitted. The SPI return value is then read out and
1294 * returned.
1295 *
1296 * @param[in] usart
1297 * A pointer to the USART peripheral register block.
1298 *
1299 * @param[in] data
1300 * Data to transmit.
1301 *
1302 * @return
1303 * Data received.
1304 ******************************************************************************/
USART_SpiTransfer(USART_TypeDef * usart,uint8_t data)1305 uint8_t USART_SpiTransfer(USART_TypeDef *usart, uint8_t data)
1306 {
1307 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1308 }
1309 usart->TXDATA = (uint32_t)data;
1310 while (!(usart->STATUS & USART_STATUS_TXC)) {
1311 }
1312 return (uint8_t)usart->RXDATA;
1313 }
1314
1315 /***************************************************************************//**
1316 * @brief
1317 * Transmit one 4-9 bit frame.
1318 *
1319 * @details
1320 * Depending on the frame length configuration, 4-8 (least significant) bits from
1321 * @p data are transmitted. If the frame length is 9, 8 bits are transmitted from
1322 * @p data and one bit as specified by CTRL register, BIT8DV field.
1323 * See USART_TxExt() for transmitting 9 bit frame with full control of
1324 * all 9 bits.
1325 *
1326 * Notice that possible parity/stop bits in asynchronous mode are not
1327 * considered part of a specified frame bit length.
1328 *
1329 * @note
1330 * This function will stall if the buffer is full until the buffer becomes available.
1331 *
1332 * @param[in] usart
1333 * A pointer to the USART/UART peripheral register block.
1334 *
1335 * @param[in] data
1336 * Data to transmit. See details above for more information.
1337 ******************************************************************************/
USART_Tx(USART_TypeDef * usart,uint8_t data)1338 void USART_Tx(USART_TypeDef *usart, uint8_t data)
1339 {
1340 /* Check that transmit buffer is empty */
1341 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1342 }
1343 usart->TXDATA = (uint32_t)data;
1344 }
1345
1346 /***************************************************************************//**
1347 * @brief
1348 * Transmit two 4-9 bit frames or one 10-16 bit frame.
1349 *
1350 * @details
1351 * Depending on the frame length configuration, 4-8 (least significant) bits from
1352 * each byte in @p data are transmitted. If frame length is 9, 8 bits are
1353 * transmitted from each byte in @p data adding one bit as specified by the CTRL
1354 * register, BIT8DV field, to each byte. See USART_TxDoubleExt()
1355 * for transmitting two 9 bit frames with full control of all 9 bits.
1356 *
1357 * If the frame length is 10-16, 10-16 (least significant) bits from @p data
1358 * are transmitted.
1359 *
1360 * Notice that possible parity/stop bits in asynchronous mode are not
1361 * considered part of a specified frame bit length.
1362 *
1363 * @note
1364 * This function will stall if the buffer is full until the buffer becomes available.
1365 *
1366 * @param[in] usart
1367 * A pointer to the USART/UART peripheral register block.
1368 *
1369 * @param[in] data
1370 * Data to transmit, the least significant byte holds the frame transmitted
1371 * first. See details above for more info.
1372 ******************************************************************************/
USART_TxDouble(USART_TypeDef * usart,uint16_t data)1373 void USART_TxDouble(USART_TypeDef *usart, uint16_t data)
1374 {
1375 /* Check that transmit buffer is empty */
1376 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1377 }
1378 usart->TXDOUBLE = (uint32_t)data;
1379 }
1380
1381 /***************************************************************************//**
1382 * @brief
1383 * Transmit two 4-9 bit frames or one 10-16 bit frame with extended control.
1384 *
1385 * @details
1386 * Notice that possible parity/stop bits in asynchronous mode are not
1387 * considered part of a specified frame bit length.
1388 *
1389 * @note
1390 * This function will stall if the buffer is full until the buffer becomes available.
1391 *
1392 * @param[in] usart
1393 * A pointer to the USART/UART peripheral register block.
1394 *
1395 * @param[in] data
1396 * Data to transmit with extended control. Contains two 16 bit words
1397 * concatenated. Least significant word holds the frame transmitted first. If the frame
1398 * length is 4-9, two frames with 4-9 least significant bits from each 16 bit
1399 * word are transmitted.
1400 * @par
1401 * If the frame length is 10-16 bits, 8 data bits are taken from the least
1402 * significant 16 bit word and the remaining bits from the other 16 bit word.
1403 * @par
1404 * Additional control bits are available as documented in the reference
1405 * manual (set to 0 if not used). For 10-16 bit frame length, these control
1406 * bits are taken from the most significant 16 bit word.
1407 ******************************************************************************/
USART_TxDoubleExt(USART_TypeDef * usart,uint32_t data)1408 void USART_TxDoubleExt(USART_TypeDef *usart, uint32_t data)
1409 {
1410 /* Check that transmit buffer is empty. */
1411 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1412 }
1413 usart->TXDOUBLEX = data;
1414 }
1415
1416 /***************************************************************************//**
1417 * @brief
1418 * Transmit one 4-9 bit frame with extended control.
1419 *
1420 * @details
1421 * Notice that possible parity/stop bits in asynchronous mode are not
1422 * considered part of a specified frame bit length.
1423 *
1424 * @note
1425 * This function will stall if the buffer is full until the buffer becomes available.
1426 *
1427 * @param[in] usart
1428 * A pointer to the USART/UART peripheral register block.
1429 *
1430 * @param[in] data
1431 * Data to transmit with extended control. Least significant bit contains
1432 * frame bits. Additional control bits are available as documented in
1433 * the reference manual (set to 0 if not used).
1434 ******************************************************************************/
USART_TxExt(USART_TypeDef * usart,uint16_t data)1435 void USART_TxExt(USART_TypeDef *usart, uint16_t data)
1436 {
1437 /* Check that the transmit buffer is empty. */
1438 while (!(usart->STATUS & USART_STATUS_TXBL)) {
1439 }
1440 usart->TXDATAX = (uint32_t)data;
1441 }
1442
1443 /** @} (end addtogroup usart) */
1444 #endif /* defined(USART_COUNT) && (USART_COUNT > 0) */
1445