1 /***************************************************************************//**
2 * @file
3 * @brief Universal synchronous/asynchronous receiver/transmitter (USART/UART)
4 * Peripheral API
5 * @author Energy Micro AS
6 * @version 3.0.0
7 *******************************************************************************
8 * @section License
9 * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
10 *******************************************************************************
11 *
12 * Permission is granted to anyone to use this software for any purpose,
13 * including commercial applications, and to alter it and redistribute it
14 * freely, subject to the following restrictions:
15 *
16 * 1. The origin of this software must not be misrepresented; you must not
17 * claim that you wrote the original software.
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 * 3. This notice may not be removed or altered from any source distribution.
21 *
22 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
23 * obligation to support this Software. Energy Micro AS is providing the
24 * Software "AS IS", with no express or implied warranties of any kind,
25 * including, but not limited to, any implied warranties of merchantability
26 * or fitness for any particular purpose or warranties against infringement
27 * of any proprietary rights of a third party.
28 *
29 * Energy Micro AS will not be liable for any consequential, incidental, or
30 * special damages, or any other relief, or for any claim by any third party,
31 * arising from your use of this Software.
32 *
33 ******************************************************************************/
34 #include "em_usart.h"
35 #include "em_cmu.h"
36 #include "em_assert.h"
37
38 /***************************************************************************//**
39 * @addtogroup EM_Library
40 * @{
41 ******************************************************************************/
42
43 /***************************************************************************//**
44 * @addtogroup USART
45 * @brief Universal Synchronous/Asynchronous Receiver/Transmitter
46 * Peripheral API
47 * @{
48 ******************************************************************************/
49
50 /*******************************************************************************
51 ******************************* DEFINES ***********************************
52 ******************************************************************************/
53
54 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
55
56
57 /** Validation of USART register block pointer reference for assert statements. */
58 #if (USART_COUNT == 1)
59 #define USART_REF_VALID(ref) ((ref) == USART0)
60
61 #elif (USART_COUNT == 2)
62 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
63
64 #elif (USART_COUNT == 3)
65 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || \
66 ((ref) == USART2))
67 #elif (USART_COUNT == 4)
68 #define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) || \
69 ((ref) == USART2) || ((ref) == USART3))
70 #else
71 #error Undefined number of USARTs.
72 #endif
73
74 #define USART_IRDA_VALID(ref) ((ref) == USART0)
75
76 #if defined(_EFM32_TINY_FAMILY)
77 #define USART_I2S_VALID(ref) ((ref) == USART1)
78 #endif
79
80 #if defined(_EFM32_GIANT_FAMILY)
81 #define USART_I2S_VALID(ref) (((ref) == USART1) || ((ref) == USART2))
82 #endif
83
84 #if (UART_COUNT == 1)
85 #define UART_REF_VALID(ref) ((ref)==UART0)
86 #elif (UART_COUNT == 2)
87 #define UART_REF_VALID(ref) (((ref)==UART0) || ((ref)==UART1))
88 #else
89 #define UART_REF_VALID(ref) (0)
90 #endif
91
92 /** @endcond */
93
94
95 /*******************************************************************************
96 ************************** GLOBAL FUNCTIONS *******************************
97 ******************************************************************************/
98
99 /***************************************************************************//**
100 * @brief
101 * Configure USART/UART operating in asynchronous mode to use a given
102 * baudrate (or as close as possible to specified baudrate).
103 *
104 * @param[in] usart
105 * Pointer to USART/UART peripheral register block.
106 *
107 * @param[in] refFreq
108 * USART/UART reference clock frequency in Hz that will be used. If set to 0,
109 * the currently configured reference clock is assumed.
110 *
111 * @param[in] baudrate
112 * Baudrate to try to achieve for USART/UART.
113 *
114 * @param[in] ovs
115 * Oversampling to be used. Normal is 16x oversampling, but lower oversampling
116 * may be used to achieve higher rates or better baudrate accuracy in some
117 * cases. Notice that lower oversampling frequency makes channel more
118 * vulnerable to bit faults during reception due to clock inaccuracies
119 * compared to link partner.
120 ******************************************************************************/
USART_BaudrateAsyncSet(USART_TypeDef * usart,uint32_t refFreq,uint32_t baudrate,USART_OVS_TypeDef ovs)121 void USART_BaudrateAsyncSet(USART_TypeDef *usart,
122 uint32_t refFreq,
123 uint32_t baudrate,
124 USART_OVS_TypeDef ovs)
125 {
126 uint32_t clkdiv;
127 uint32_t oversample;
128
129 /* Inhibit divide by 0 */
130 EFM_ASSERT(baudrate);
131
132 /*
133 * We want to use integer division to avoid forcing in float division
134 * utils, and yet keep rounding effect errors to a minimum.
135 *
136 * CLKDIV in asynchronous mode is given by:
137 *
138 * CLKDIV = 256 * (fHFPERCLK/(oversample * br) - 1)
139 * or
140 * CLKDIV = (256 * fHFPERCLK)/(oversample * br) - 256
141 *
142 * The basic problem with integer division in the above formula is that
143 * the dividend (256 * fHFPERCLK) may become higher than max 32 bit
144 * integer. Yet, we want to evaluate dividend first before dividing in
145 * order to get as small rounding effects as possible. We do not want
146 * to make too harsh restrictions on max fHFPERCLK value either.
147 *
148 * One can possibly factorize 256 and oversample/br. However,
149 * since the last 6 bits of CLKDIV are don't care, we can base our
150 * integer arithmetic on the below formula
151 *
152 * CLKDIV / 64 = (4 * fHFPERCLK)/(oversample * br) - 4
153 *
154 * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK
155 * up to 1GHz without overflowing a 32 bit value!
156 */
157
158 /* HFPERCLK used to clock all USART/UART peripheral modules */
159 if (!refFreq)
160 {
161 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
162 }
163
164 /* Map oversampling */
165 switch (ovs)
166 {
167 case USART_CTRL_OVS_X16:
168 EFM_ASSERT(baudrate <= (refFreq / 16));
169 oversample = 16;
170 break;
171
172 case USART_CTRL_OVS_X8:
173 EFM_ASSERT(baudrate <= (refFreq / 8));
174 oversample = 8;
175 break;
176
177 case USART_CTRL_OVS_X6:
178 EFM_ASSERT(baudrate <= (refFreq / 6));
179 oversample = 6;
180 break;
181
182 case USART_CTRL_OVS_X4:
183 EFM_ASSERT(baudrate <= (refFreq / 4));
184 oversample = 4;
185 break;
186
187 default:
188 /* Invalid input */
189 EFM_ASSERT(0);
190 return;
191 }
192
193 /* Calculate and set CLKDIV with fractional bits */
194 clkdiv = 4 * refFreq + (oversample * baudrate) / 2;
195 clkdiv /= (oversample * baudrate);
196 clkdiv -= 4;
197 clkdiv *= 64;
198
199 usart->CTRL &= ~_USART_CTRL_OVS_MASK;
200 usart->CTRL |= ovs;
201 usart->CLKDIV = clkdiv;
202 }
203
204
205 /***************************************************************************//**
206 * @brief
207 * Calculate baudrate for USART/UART given reference frequency, clock division
208 * and oversampling rate (if async mode).
209 *
210 * @details
211 * This function returns the baudrate that a USART/UART module will use if
212 * configured with the given frequency, clock divisor and mode. Notice that
213 * this function will not use actual HW configuration. It can be used
214 * to determinate if a given configuration is sufficiently accurate for the
215 * application.
216 *
217 * @param[in] refFreq
218 * USART/UART HF peripheral frequency used.
219 *
220 * @param[in] clkdiv
221 * Clock division factor to be used.
222 *
223 * @param[in] syncmode
224 * @li true - synchronous mode operation.
225 * @li false - asynchronous mode operation.
226 *
227 * @param[in] ovs
228 * Oversampling used if asynchronous mode. Not used if @p syncmode is true.
229 *
230 * @return
231 * Baudrate with given settings.
232 ******************************************************************************/
USART_BaudrateCalc(uint32_t refFreq,uint32_t clkdiv,bool syncmode,USART_OVS_TypeDef ovs)233 uint32_t USART_BaudrateCalc(uint32_t refFreq,
234 uint32_t clkdiv,
235 bool syncmode,
236 USART_OVS_TypeDef ovs)
237 {
238 uint32_t oversample;
239 uint32_t divisor;
240 uint32_t factor;
241 uint32_t remainder;
242 uint32_t quotient;
243 uint32_t br;
244
245 /* Mask out unused bits */
246 clkdiv &= _USART_CLKDIV_MASK;
247
248 /* We want to use integer division to avoid forcing in float division */
249 /* utils, and yet keep rounding effect errors to a minimum. */
250
251 /* Baudrate calculation depends on if synchronous or asynchronous mode */
252 if (syncmode)
253 {
254 /*
255 * Baudrate is given by:
256 *
257 * br = fHFPERCLK/(2 * (1 + (CLKDIV / 256)))
258 *
259 * which can be rewritten to
260 *
261 * br = (128 * fHFPERCLK)/(256 + CLKDIV)
262 */
263 oversample = 1; /* Not used in sync mode, ie 1 */
264 factor = 128;
265 }
266 else
267 {
268 /*
269 * Baudrate in asynchronous mode is given by:
270 *
271 * br = fHFPERCLK/(oversample * (1 + (CLKDIV / 256)))
272 *
273 * which can be rewritten to
274 *
275 * br = (256 * fHFPERCLK)/(oversample * (256 + CLKDIV))
276 *
277 * First of all we can reduce the 256 factor of the dividend with
278 * (part of) oversample part of the divisor.
279 */
280
281 switch (ovs)
282 {
283 case USART_CTRL_OVS_X16:
284 oversample = 1;
285 factor = 256 / 16;
286 break;
287
288 case USART_CTRL_OVS_X8:
289 oversample = 1;
290 factor = 256 / 8;
291 break;
292
293 case USART_CTRL_OVS_X6:
294 oversample = 3;
295 factor = 256 / 2;
296 break;
297
298 default:
299 oversample = 1;
300 factor = 256 / 4;
301 break;
302 }
303 }
304
305 /*
306 * The basic problem with integer division in the above formula is that
307 * the dividend (factor * fHFPERCLK) may become higher than max 32 bit
308 * integer. Yet we want to evaluate dividend first before dividing in
309 * order to get as small rounding effects as possible. We do not want
310 * to make too harsh restrictions on max fHFPERCLK value either.
311 *
312 * For division a/b, we can write
313 *
314 * a = qb + r
315 *
316 * where q is the quotient and r is the remainder, both integers.
317 *
318 * The orignal baudrate formula can be rewritten as
319 *
320 * br = xa / b = x(qb + r)/b = xq + xr/b
321 *
322 * where x is 'factor', a is 'refFreq' and b is 'divisor', referring to
323 * variable names.
324 */
325
326 /* Divisor will never exceed max 32 bit value since clkdiv <= 0x1fffc0 */
327 /* and 'oversample' has been reduced to <= 3. */
328 divisor = oversample * (256 + clkdiv);
329
330 quotient = refFreq / divisor;
331 remainder = refFreq % divisor;
332
333 /* factor <= 128 and since divisor >= 256, the below cannot exceed max */
334 /* 32 bit value. */
335 br = factor * quotient;
336
337 /*
338 * factor <= 128 and remainder < (oversample*(256 + clkdiv)), which
339 * means dividend (factor * remainder) worst case is
340 * 128*(3 * (256 + 0x1fffc0)) = 0x30012000.
341 */
342 br += (factor * remainder) / divisor;
343
344 return br;
345 }
346
347
348 /***************************************************************************//**
349 * @brief
350 * Get current baudrate for USART/UART.
351 *
352 * @details
353 * This function returns the actual baudrate (not considering oscillator
354 * inaccuracies) used by a USART/UART peripheral.
355 *
356 * @param[in] usart
357 * Pointer to USART/UART peripheral register block.
358 *
359 * @return
360 * Current baudrate.
361 ******************************************************************************/
USART_BaudrateGet(USART_TypeDef * usart)362 uint32_t USART_BaudrateGet(USART_TypeDef *usart)
363 {
364 uint32_t freq;
365 USART_OVS_TypeDef ovs;
366 bool syncmode;
367
368 if (usart->CTRL & USART_CTRL_SYNC)
369 {
370 syncmode = true;
371 }
372 else
373 {
374 syncmode = false;
375 }
376
377 /* HFPERCLK used to clock all USART/UART peripheral modules */
378 freq = CMU_ClockFreqGet(cmuClock_HFPER);
379 ovs = (USART_OVS_TypeDef)(usart->CTRL & _USART_CTRL_OVS_MASK);
380 return USART_BaudrateCalc(freq, usart->CLKDIV, syncmode, ovs);
381 }
382
383
384 /***************************************************************************//**
385 * @brief
386 * Configure USART operating in synchronous mode to use a given baudrate
387 * (or as close as possible to specified baudrate).
388 *
389 * @details
390 * The configuration will be set to use a baudrate <= the specified baudrate
391 * in order to ensure that the baudrate does not exceed the specified value.
392 *
393 * Fractional clock division is suppressed, although the HW design allows it.
394 * It could cause half clock cycles to exceed specified limit, and thus
395 * potentially violate specifications for the slave device. In some special
396 * situations fractional clock division may be useful even in synchronous
397 * mode, but in those cases it must be directly adjusted, possibly assisted
398 * by USART_BaudrateCalc():
399 *
400 * @param[in] usart
401 * Pointer to USART peripheral register block. (Cannot be used on UART
402 * modules.)
403 *
404 * @param[in] refFreq
405 * USART reference clock frequency in Hz that will be used. If set to 0,
406 * the currently configured reference clock is assumed.
407 *
408 * @param[in] baudrate
409 * Baudrate to try to achieve for USART.
410 ******************************************************************************/
USART_BaudrateSyncSet(USART_TypeDef * usart,uint32_t refFreq,uint32_t baudrate)411 void USART_BaudrateSyncSet(USART_TypeDef *usart, uint32_t refFreq, uint32_t baudrate)
412 {
413 uint32_t clkdiv;
414
415 /* Inhibit divide by 0 */
416 EFM_ASSERT(baudrate);
417
418 /*
419 * We want to use integer division to avoid forcing in float division
420 * utils, and yet keep rounding effect errors to a minimum.
421 *
422 * CLKDIV in synchronous mode is given by:
423 *
424 * CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1)
425 * or
426 * CLKDIV = (256 * fHFPERCLK)/(2 * br) - 256 = (128 * fHFPERCLK)/br - 256
427 *
428 * The basic problem with integer division in the above formula is that
429 * the dividend (128 * fHFPERCLK) may become higher than max 32 bit
430 * integer. Yet, we want to evaluate dividend first before dividing in
431 * order to get as small rounding effects as possible. We do not want
432 * to make too harsh restrictions on max fHFPERCLK value either.
433 *
434 * One can possibly factorize 128 and br. However, since the last
435 * 6 bits of CLKDIV are don't care, we can base our integer arithmetic
436 * on the below formula without loosing any extra precision:
437 *
438 * CLKDIV / 64 = (2 * fHFPERCLK)/br - 4
439 *
440 * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK
441 * up to 2GHz without overflowing a 32 bit value!
442 */
443
444 /* HFPERCLK used to clock all USART/UART peripheral modules */
445 if (!refFreq)
446 {
447 refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
448 }
449
450 /* Calculate and set CLKDIV with fractional bits */
451 clkdiv = 2 * refFreq;
452 clkdiv += baudrate - 1;
453 clkdiv /= baudrate;
454 clkdiv -= 4;
455 clkdiv *= 64;
456 /* Make sure we don't use fractional bits by rounding CLKDIV */
457 /* up (and thus reducing baudrate, not increasing baudrate above */
458 /* specified value). */
459 clkdiv += 0xc0;
460 clkdiv &= 0xffffff00;
461
462 /* Verify that resulting clock divider is within limits */
463 EFM_ASSERT(clkdiv <= _USART_CLKDIV_MASK);
464
465 /* If EFM_ASSERT is not enabled, make sure we don't write to reserved bits */
466 clkdiv &= _USART_CLKDIV_DIV_MASK;
467
468 usart->CLKDIV = clkdiv;
469 }
470
471
472 /***************************************************************************//**
473 * @brief
474 * Enable/disable USART/UART receiver and/or transmitter.
475 *
476 * @details
477 * Notice that this function does not do any configuration. Enabling should
478 * normally be done after initialization is done (if not enabled as part
479 * of init).
480 *
481 * @param[in] usart
482 * Pointer to USART/UART peripheral register block.
483 *
484 * @param[in] enable
485 * Select status for receiver/transmitter.
486 ******************************************************************************/
USART_Enable(USART_TypeDef * usart,USART_Enable_TypeDef enable)487 void USART_Enable(USART_TypeDef *usart, USART_Enable_TypeDef enable)
488 {
489 uint32_t tmp;
490
491 /* Make sure the module exists on the selected chip */
492 EFM_ASSERT(USART_REF_VALID(usart)||(UART_REF_VALID(usart)));
493
494 /* Disable as specified */
495 tmp = ~((uint32_t)(enable));
496 tmp &= _USART_CMD_RXEN_MASK | _USART_CMD_TXEN_MASK;
497 usart->CMD = tmp << 1;
498
499 /* Enable as specified */
500 usart->CMD = (uint32_t)(enable);
501 }
502
503
504 /***************************************************************************//**
505 * @brief
506 * Init USART/UART for normal asynchronous mode.
507 *
508 * @details
509 * This function will configure basic settings in order to operate in normal
510 * asynchronous mode.
511 *
512 * Special control setup not covered by this function must be done after
513 * using this function by direct modification of the CTRL register.
514 *
515 * Notice that pins used by the USART/UART module must be properly configured
516 * by the user explicitly, in order for the USART/UART to work as intended.
517 * (When configuring pins, one should remember to consider the sequence of
518 * configuration, in order to avoid unintended pulses/glitches on output
519 * pins.)
520 *
521 * @param[in] usart
522 * Pointer to USART/UART peripheral register block.
523 *
524 * @param[in] init
525 * Pointer to initialization structure used to configure basic async setup.
526 ******************************************************************************/
USART_InitAsync(USART_TypeDef * usart,const USART_InitAsync_TypeDef * init)527 void USART_InitAsync(USART_TypeDef *usart, const USART_InitAsync_TypeDef *init)
528 {
529 /* Make sure the module exists on the selected chip */
530 EFM_ASSERT(USART_REF_VALID(usart)||UART_REF_VALID(usart));
531
532 /* Init USART registers to HW reset state. */
533 USART_Reset(usart);
534
535 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_TINY_FAMILY)
536 /* Disable majority vote if specified. */
537 if (init->mvdis)
538 {
539 usart->CTRL |= USART_CTRL_MVDIS;
540 }
541
542 /* Configure PRS input mode. */
543 if (init->prsRxEnable)
544 {
545 usart->INPUT = (uint32_t)init->prsRxCh | USART_INPUT_RXPRS;
546 }
547 #endif
548
549 /* Configure databits, stopbits and parity */
550 usart->FRAME = (uint32_t)(init->databits) |
551 (uint32_t)(init->stopbits) |
552 (uint32_t)(init->parity);
553
554 /* Configure baudrate */
555 USART_BaudrateAsyncSet(usart, init->refFreq, init->baudrate, init->oversampling);
556
557 /* Finally enable (as specified) */
558 usart->CMD = (uint32_t)(init->enable);
559 }
560
561
562 /***************************************************************************//**
563 * @brief
564 * Init USART for synchronous mode.
565 *
566 * @details
567 * This function will configure basic settings in order to operate in
568 * synchronous mode.
569 *
570 * Special control setup not covered by this function must be done after
571 * using this function by direct modification of the CTRL register.
572 *
573 * Notice that pins used by the USART module must be properly configured
574 * by the user explicitly, in order for the USART to work as intended.
575 * (When configuring pins, one should remember to consider the sequence of
576 * configuration, in order to avoid unintended pulses/glitches on output
577 * pins.)
578 *
579 * @param[in] usart
580 * Pointer to USART peripheral register block. (UART does not support this
581 * mode.)
582 *
583 * @param[in] init
584 * Pointer to initialization structure used to configure basic async setup.
585 ******************************************************************************/
USART_InitSync(USART_TypeDef * usart,const USART_InitSync_TypeDef * init)586 void USART_InitSync(USART_TypeDef *usart, const USART_InitSync_TypeDef *init)
587 {
588 /* Make sure the module exists on the selected chip */
589 EFM_ASSERT(USART_REF_VALID(usart));
590
591 /* Init USART registers to HW reset state. */
592 USART_Reset(usart);
593
594 /* Set bits for synchronous mode */
595 usart->CTRL |= (USART_CTRL_SYNC) |
596 ((uint32_t)init->clockMode) |
597 (init->msbf ? USART_CTRL_MSBF : 0);
598
599 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_TINY_FAMILY)
600 usart->CTRL |= (init->prsRxEnable ? USART_INPUT_RXPRS : 0) |
601 (init->autoTx ? USART_CTRL_AUTOTX : 0);
602 #endif
603
604 /* Configure databits, leave stopbits and parity at reset default (not used) */
605 usart->FRAME = ((uint32_t)(init->databits)) |
606 (USART_FRAME_STOPBITS_DEFAULT) |
607 (USART_FRAME_PARITY_DEFAULT);
608
609 /* Configure baudrate */
610 USART_BaudrateSyncSet(usart, init->refFreq, init->baudrate);
611
612 /* Finally enable (as specified) */
613 if (init->master)
614 {
615 usart->CMD = USART_CMD_MASTEREN;
616 }
617
618 usart->CMD = (uint32_t)(init->enable);
619 }
620
621
622 /***************************************************************************//**
623 * @brief
624 * Init USART0 for asynchronous IrDA mode.
625 *
626 * @details
627 * This function will configure basic settings in order to operate in
628 * asynchronous IrDA mode.
629 *
630 * Special control setup not covered by this function must be done after
631 * using this function by direct modification of the CTRL and IRCTRL
632 * registers.
633 *
634 * Notice that pins used by the USART/UART module must be properly configured
635 * by the user explicitly, in order for the USART/UART to work as intended.
636 * (When configuring pins, one should remember to consider the sequence of
637 * configuration, in order to avoid unintended pulses/glitches on output
638 * pins.)
639 *
640 * @param[in] init
641 * Pointer to initialization structure used to configure async IrDA setup.
642 *
643 * @note
644 * This function only applies to USART0 as IrDA is not supported on the other
645 * USART modules.
646 *
647 ******************************************************************************/
USART_InitIrDA(const USART_InitIrDA_TypeDef * init)648 void USART_InitIrDA(const USART_InitIrDA_TypeDef *init)
649 {
650 /* Init USART0 as async device */
651 USART_InitAsync(USART0, &(init->async));
652
653 /* Set IrDA modulation to RZI (return-to-zero-inverted) */
654 USART0->CTRL |= USART_CTRL_TXINV;
655
656 /* Invert Rx signal before demodulator if enabled */
657 if (init->irRxInv)
658 {
659 USART0->CTRL |= USART_CTRL_RXINV;
660 }
661
662 /* Configure IrDA */
663 USART0->IRCTRL |= (uint32_t)init->irPw |
664 (uint32_t)init->irPrsSel |
665 ((uint32_t)init->irFilt << _USART_IRCTRL_IRFILT_SHIFT) |
666 ((uint32_t)init->irPrsEn << _USART_IRCTRL_IRPRSEN_SHIFT);
667
668 /* Enable IrDA */
669 USART0->IRCTRL |= USART_IRCTRL_IREN;
670 }
671
672
673 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_TINY_FAMILY)
674 /***************************************************************************//**
675 * @brief
676 * Init USART for I2S mode.
677 *
678 * @details
679 * This function will configure basic settings in order to operate in I2S
680 * mode.
681 *
682 * Special control setup not covered by this function must be done after
683 * using this function by direct modification of the CTRL and I2SCTRL
684 * registers.
685 *
686 * Notice that pins used by the USART module must be properly configured
687 * by the user explicitly, in order for the USART to work as intended.
688 * (When configuring pins, one should remember to consider the sequence of
689 * configuration, in order to avoid unintended pulses/glitches on output
690 * pins.)
691 *
692 * @param[in] usart
693 * Pointer to USART peripheral register block. (UART does not support this
694 * mode.)
695 *
696 * @param[in] init
697 * Pointer to initialization structure used to configure basic I2S setup.
698 *
699 * @note
700 * This function does not apply to all USART's. Refer to chip manuals.
701 *
702 ******************************************************************************/
USART_InitI2s(USART_TypeDef * usart,USART_InitI2s_TypeDef * init)703 void USART_InitI2s(USART_TypeDef *usart, USART_InitI2s_TypeDef *init)
704 {
705 USART_Enable_TypeDef enable;
706
707 /* Make sure the module exists on the selected chip */
708 EFM_ASSERT(USART_I2S_VALID(usart));
709
710 /* Override the enable setting. */
711 enable = init->sync.enable;
712 init->sync.enable = usartDisable;
713
714 /* Init USART as a sync device. */
715 USART_InitSync(usart, &init->sync);
716
717 /* Configure and enable I2CCTRL register acording to selected mode. */
718 usart->I2SCTRL = ((uint32_t)init->format) |
719 ((uint32_t)init->justify) |
720 (init->delay ? USART_I2SCTRL_DELAY : 0) |
721 (init->dmaSplit ? USART_I2SCTRL_DMASPLIT : 0) |
722 (init->mono ? USART_I2SCTRL_MONO : 0) |
723 (USART_I2SCTRL_EN);
724
725 if (enable != usartDisable)
726 {
727 USART_Enable(usart, enable);
728 }
729 }
730
731
732 /***************************************************************************//**
733 * @brief
734 * Initialize automatic transmissions using PRS channel as trigger
735 * @note
736 * Initialize USART with USART_Init() before setting up PRS configuration
737 *
738 * @param[in] usart Pointer to USART to configure
739 * @param[in] init Pointer to initialization structure
740 ******************************************************************************/
USART_InitPrsTrigger(USART_TypeDef * usart,const USART_PrsTriggerInit_TypeDef * init)741 void USART_InitPrsTrigger(USART_TypeDef *usart, const USART_PrsTriggerInit_TypeDef *init)
742 {
743 uint32_t trigctrl;
744
745 /* Clear values that will be reconfigured */
746 trigctrl = usart->TRIGCTRL & ~(_USART_TRIGCTRL_RXTEN_MASK|
747 _USART_TRIGCTRL_TXTEN_MASK|
748 #if defined(_EFM32_GIANT_FAMILY)
749 _USART_TRIGCTRL_AUTOTXTEN_MASK|
750 #endif
751 _USART_TRIGCTRL_TSEL_MASK);
752
753 #if defined(_EFM32_GIANT_FAMILY)
754 if(init->autoTxTriggerEnable)
755 {
756 trigctrl |= USART_TRIGCTRL_AUTOTXTEN;
757 }
758 #endif
759 if(init->txTriggerEnable)
760 {
761 trigctrl |= USART_TRIGCTRL_TXTEN;
762 }
763 if(init->rxTriggerEnable)
764 {
765 trigctrl |= USART_TRIGCTRL_RXTEN;
766 }
767 trigctrl |= init->prsTriggerChannel;
768
769 /* Enable new configuration */
770 usart->TRIGCTRL = trigctrl;
771 }
772 #endif
773
774
775 /***************************************************************************//**
776 * @brief
777 * Reset USART/UART to same state as after a HW reset.
778 *
779 * @param[in] usart
780 * Pointer to USART/UART peripheral register block.
781 ******************************************************************************/
USART_Reset(USART_TypeDef * usart)782 void USART_Reset(USART_TypeDef *usart)
783 {
784 /* Make sure the module exists on the selected chip */
785 EFM_ASSERT(USART_REF_VALID(usart)||UART_REF_VALID(usart));
786
787 /* Make sure disabled first, before resetting other registers */
788 usart->CMD = USART_CMD_RXDIS | USART_CMD_TXDIS | USART_CMD_MASTERDIS |
789 USART_CMD_RXBLOCKDIS | USART_CMD_TXTRIDIS | USART_CMD_CLEARTX | USART_CMD_CLEARRX;
790 usart->CTRL = _USART_CTRL_RESETVALUE;
791 usart->FRAME = _USART_FRAME_RESETVALUE;
792 usart->TRIGCTRL = _USART_TRIGCTRL_RESETVALUE;
793 usart->CLKDIV = _USART_CLKDIV_RESETVALUE;
794 usart->IEN = _USART_IEN_RESETVALUE;
795 usart->IFC = _USART_IFC_MASK;
796 usart->ROUTE = _USART_ROUTE_RESETVALUE;
797
798 if (USART_IRDA_VALID(usart))
799 {
800 usart->IRCTRL = _USART_IRCTRL_RESETVALUE;
801 }
802
803 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_TINY_FAMILY)
804 usart->INPUT = _USART_INPUT_RESETVALUE;
805
806 if (USART_I2S_VALID(usart))
807 {
808 usart->I2SCTRL = _USART_I2SCTRL_RESETVALUE;
809 }
810 #endif
811
812 /* Do not reset route register, setting should be done independently */
813 }
814
815
816 /***************************************************************************//**
817 * @brief
818 * Receive one 4-8 bit frame, (or part of 10-16 bit frame).
819 *
820 * @details
821 * This function is normally used to receive one frame when operating with
822 * frame length 4-8 bits. Please refer to USART_RxExt() for reception of
823 * 9 bit frames.
824 *
825 * Notice that possible parity/stop bits in asynchronous mode are not
826 * considered part of specified frame bit length.
827 *
828 * @note
829 * This function will stall if buffer is empty, until data is received.
830 *
831 * @param[in] usart
832 * Pointer to USART/UART peripheral register block.
833 *
834 * @return
835 * Data received.
836 ******************************************************************************/
USART_Rx(USART_TypeDef * usart)837 uint8_t USART_Rx(USART_TypeDef *usart)
838 {
839 while (!(usart->STATUS & USART_STATUS_RXDATAV))
840 ;
841
842 return (uint8_t)(usart->RXDATA);
843 }
844
845
846 /***************************************************************************//**
847 * @brief
848 * Receive two 4-8 bit frames, or one 10-16 bit frame.
849 *
850 * @details
851 * This function is normally used to receive one frame when operating with
852 * frame length 10-16 bits. Please refer to USART_RxDoubleExt() for reception
853 * of two 9 bit frames.
854 *
855 * Notice that possible parity/stop bits in asynchronous mode are not
856 * considered part of specified frame bit length.
857 *
858 * @note
859 * This function will stall if buffer is empty, until data is received.
860 *
861 * @param[in] usart
862 * Pointer to USART/UART peripheral register block.
863 *
864 * @return
865 * Data received.
866 ******************************************************************************/
USART_RxDouble(USART_TypeDef * usart)867 uint16_t USART_RxDouble(USART_TypeDef *usart)
868 {
869 while (!(usart->STATUS & USART_STATUS_RXFULL))
870 ;
871
872 return (uint16_t)(usart->RXDOUBLE);
873 }
874
875
876 /***************************************************************************//**
877 * @brief
878 * Receive two 4-9 bit frames, or one 10-16 bit frame with extended
879 * information.
880 *
881 * @details
882 * This function is normally used to receive one frame when operating with
883 * frame length 10-16 bits and additional RX status information is required.
884 *
885 * Notice that possible parity/stop bits in asynchronous mode are not
886 * considered part of specified frame bit length.
887 *
888 * @note
889 * This function will stall if buffer is empty, until data is received.
890 *
891 * @param[in] usart
892 * Pointer to USART/UART peripheral register block.
893 *
894 * @return
895 * Data received.
896 ******************************************************************************/
USART_RxDoubleExt(USART_TypeDef * usart)897 uint32_t USART_RxDoubleExt(USART_TypeDef *usart)
898 {
899 while (!(usart->STATUS & USART_STATUS_RXFULL))
900 ;
901
902 return usart->RXDOUBLEX;
903 }
904
905
906 /***************************************************************************//**
907 * @brief
908 * Receive one 4-9 bit frame, (or part of 10-16 bit frame) with extended
909 * information.
910 *
911 * @details
912 * This function is normally used to receive one frame when operating with
913 * frame length 4-9 bits and additional RX status information is required.
914 *
915 * Notice that possible parity/stop bits in asynchronous mode are not
916 * considered part of specified frame bit length.
917 *
918 * @note
919 * This function will stall if buffer is empty, until data is received.
920 *
921 * @param[in] usart
922 * Pointer to USART/UART peripheral register block.
923 *
924 * @return
925 * Data received.
926 ******************************************************************************/
USART_RxExt(USART_TypeDef * usart)927 uint16_t USART_RxExt(USART_TypeDef *usart)
928 {
929 while (!(usart->STATUS & USART_STATUS_RXDATAV))
930 ;
931
932 return (uint16_t)(usart->RXDATAX);
933 }
934
935
936 /***************************************************************************//**
937 * @brief
938 * Transmit one 4-9 bit frame.
939 *
940 * @details
941 * Depending on frame length configuration, 4-8 (least significant) bits from
942 * @p data are transmitted. If frame length is 9, 8 bits are transmitted from
943 * @p data and one bit as specified by CTRL register, BIT8DV field. Please
944 * refer to USART_TxExt() for transmitting 9 bit frame with full control of
945 * all 9 bits.
946 *
947 * Notice that possible parity/stop bits in asynchronous mode are not
948 * considered part of specified frame bit length.
949 *
950 * @note
951 * This function will stall if buffer is full, until buffer becomes available.
952 *
953 * @param[in] usart
954 * Pointer to USART/UART peripheral register block.
955 *
956 * @param[in] data
957 * Data to transmit. See details above for further info.
958 ******************************************************************************/
USART_Tx(USART_TypeDef * usart,uint8_t data)959 void USART_Tx(USART_TypeDef *usart, uint8_t data)
960 {
961 /* Check that transmit buffer is empty */
962 while (!(usart->STATUS & USART_STATUS_TXBL));
963 usart->TXDATA = (uint32_t)data;
964 }
965
966
967 /***************************************************************************//**
968 * @brief
969 * Transmit two 4-9 bit frames, or one 10-16 bit frame.
970 *
971 * @details
972 * Depending on frame length configuration, 4-8 (least significant) bits from
973 * each byte in @p data are transmitted. If frame length is 9, 8 bits are
974 * transmitted from each byte in @p data adding one bit as specified by CTRL
975 * register, BIT8DV field, to each byte. Please refer to USART_TxDoubleExt()
976 * for transmitting two 9 bit frames with full control of all 9 bits.
977 *
978 * If frame length is 10-16, 10-16 (least significant) bits from @p data
979 * are transmitted.
980 *
981 * Notice that possible parity/stop bits in asynchronous mode are not
982 * considered part of specified frame bit length.
983 *
984 * @note
985 * This function will stall if buffer is full, until buffer becomes available.
986 *
987 * @param[in] usart
988 * Pointer to USART/UART peripheral register block.
989 *
990 * @param[in] data
991 * Data to transmit, the least significant byte holds the frame transmitted
992 * first. See details above for further info.
993 ******************************************************************************/
USART_TxDouble(USART_TypeDef * usart,uint16_t data)994 void USART_TxDouble(USART_TypeDef *usart, uint16_t data)
995 {
996 /* Check that transmit buffer is empty */
997 while (!(usart->STATUS & USART_STATUS_TXBL))
998 ;
999 usart->TXDOUBLE = (uint32_t)data;
1000 }
1001
1002
1003 /***************************************************************************//**
1004 * @brief
1005 * Transmit two 4-9 bit frames, or one 10-16 bit frame with extended control.
1006 *
1007 * @details
1008 * Notice that possible parity/stop bits in asynchronous mode are not
1009 * considered part of specified frame bit length.
1010 *
1011 * @note
1012 * This function will stall if buffer is full, until buffer becomes available.
1013 *
1014 * @param[in] usart
1015 * Pointer to USART/UART peripheral register block.
1016 *
1017 * @param[in] data
1018 * Data to transmit with extended control. Contains two 16 bit words
1019 * concatenated. Least significant word holds frame transitted first. If frame
1020 * length is 4-9, two frames with 4-9 least significant bits from each 16 bit
1021 * word are transmitted.
1022 * @par
1023 * If frame length is 10-16 bits, 8 data bits are taken from the least
1024 * significant 16 bit word, and the remaining bits from the other 16 bit word.
1025 * @par
1026 * Additional control bits are available as documented in the EFM32 reference
1027 * manual (set to 0 if not used). For 10-16 bit frame length, these control
1028 * bits are taken from the most significant 16 bit word.
1029 ******************************************************************************/
USART_TxDoubleExt(USART_TypeDef * usart,uint32_t data)1030 void USART_TxDoubleExt(USART_TypeDef *usart, uint32_t data)
1031 {
1032 /* Check that transmit buffer is empty */
1033 while (!(usart->STATUS & USART_STATUS_TXBL))
1034 ;
1035 usart->TXDOUBLEX = data;
1036 }
1037
1038
1039 /***************************************************************************//**
1040 * @brief
1041 * Transmit one 4-9 bit frame with extended control.
1042 *
1043 * @details
1044 * Notice that possible parity/stop bits in asynchronous mode are not
1045 * considered part of specified frame bit length.
1046 *
1047 * @note
1048 * This function will stall if buffer is full, until buffer becomes available.
1049 *
1050 * @param[in] usart
1051 * Pointer to USART/UART peripheral register block.
1052 *
1053 * @param[in] data
1054 * Data to transmit with extended control. Least significant bits contains
1055 * frame bits, and additional control bits are available as documented in
1056 * the EFM32 reference manual (set to 0 if not used).
1057 ******************************************************************************/
USART_TxExt(USART_TypeDef * usart,uint16_t data)1058 void USART_TxExt(USART_TypeDef *usart, uint16_t data)
1059 {
1060 /* Check that transmit buffer is empty */
1061 while (!(usart->STATUS & USART_STATUS_TXBL))
1062 ;
1063 usart->TXDATAX = (uint32_t)data;
1064 }
1065
1066
1067 /** @} (end addtogroup USART) */
1068 /** @} (end addtogroup EM_Library) */
1069