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