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