1 /***************************************************************************//**
2  * @file
3  * @brief Universal asynchronous receiver/transmitter (EUSART) peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "em_eusart.h"
32 #if defined(EUART_PRESENT) || defined(EUSART_PRESENT)
33 #include "em_cmu.h"
34 #include <stddef.h>
35 
36 /*******************************************************************************
37  *********************************   DEFINES   *********************************
38  ******************************************************************************/
39 
40 #if defined(EUART_PRESENT)
41   #define EUSART_REF_VALID(ref)    ((ref) == EUART0)
42   #define EUSART_EM2_CAPABLE(ref)  (true)
43   #define EUSART_RX_FIFO_SIZE  4u
44 #elif defined(EUSART_PRESENT)
45   #define EUSART_REF_VALID(ref)    (EUSART_NUM(ref) != -1)
46   #define EUSART_RX_FIFO_SIZE  16u
47 #endif
48 
49 /*******************************************************************************
50  **************************   LOCAL VARIABLES   ********************************
51  ******************************************************************************/
52 #if defined(EUSART_DALICFG_DALIEN)
53 static uint8_t dali_tx_nb_packets[EUSART_COUNT];
54 static uint8_t dali_rx_nb_packets[EUSART_COUNT];
55 #endif /* EUSART_DALICFG_DALIEN */
56 
57 /*******************************************************************************
58  **************************   LOCAL FUNCTIONS   ********************************
59  ******************************************************************************/
60 
61 static CMU_Clock_TypeDef EUSART_ClockGet(EUSART_TypeDef *eusart);
62 
63 static void EUSART_AsyncInitCommon(EUSART_TypeDef *eusart,
64                                    const EUSART_UartInit_TypeDef *init,
65                                    const EUSART_IrDAInit_TypeDef *irdaInit,
66                                    const EUSART_DaliInit_TypeDef *daliInit);
67 
68 #if defined(EUSART_PRESENT)
69 static void EUSART_SyncInitCommon(EUSART_TypeDef *eusart,
70                                   const EUSART_SpiInit_TypeDef  *init);
71 #endif
72 
73 /***************************************************************************//**
74  * Wait for ongoing sync of register(s) to the low-frequency domain to complete.
75  *
76  * @param eusart Pointer to the EUSART peripheral register block.
77  * @param mask A bitmask corresponding to SYNCBUSY register defined bits,
78  *             indicating registers that must complete any ongoing
79  *             synchronization.
80  ******************************************************************************/
eusart_sync(EUSART_TypeDef * eusart,uint32_t mask)81 __STATIC_INLINE void eusart_sync(EUSART_TypeDef *eusart, uint32_t mask)
82 {
83   // Wait for any pending previous write operation to have been completed
84   // in the low-frequency domain.
85   while ((eusart->SYNCBUSY & mask) != 0U) {
86   }
87 }
88 
89 /***************************************************************************//**
90  *   Calculate baudrate for a given reference frequency, clock division,
91  *   and oversampling rate.
92  ******************************************************************************/
93 __STATIC_INLINE uint32_t EUSART_AsyncBaudrateCalc(uint32_t refFreq,
94                                                   uint32_t clkdiv,
95                                                   EUSART_OVS_TypeDef ovs);
96 
97 /***************************************************************************//**
98  *   Execute the EUSART peripheral disabling sequence.
99  ******************************************************************************/
100 __STATIC_INLINE void EUSART_Disable(EUSART_TypeDef *eusart);
101 
102 /*******************************************************************************
103  **************************   GLOBAL FUNCTIONS   *******************************
104  ******************************************************************************/
105 
106 /***************************************************************************//**
107  * Initializes the EUSART when used with the high frequency clock.
108  ******************************************************************************/
EUSART_UartInitHf(EUSART_TypeDef * eusart,const EUSART_UartInit_TypeDef * init)109 void EUSART_UartInitHf(EUSART_TypeDef *eusart, const EUSART_UartInit_TypeDef *init)
110 {
111   // Make sure the module exists on the selected chip.
112   EFM_ASSERT(EUSART_REF_VALID(eusart));
113   // Init structure must be provided.
114   EFM_ASSERT(init);
115 
116   // Assert features specific to HF.
117   // The oversampling must not be disabled when using a high frequency clock.
118   EFM_ASSERT(init->oversampling != eusartOVS0);
119 
120   // Uart mode only supports up to 9 databits frame.
121   EFM_ASSERT(init->databits <= eusartDataBits9);
122 
123   // Initialize EUSART with common features to HF and LF.
124   EUSART_AsyncInitCommon(eusart, init, NULL, NULL);
125 }
126 
127 /***************************************************************************//**
128  * Initializes the EUSART when used with the low frequency clock.
129  *
130  * @note (1) When EUSART oversampling is set to eusartOVS0 (Disable), the peripheral
131  *           clock frequency must be at least three times higher than the
132  *           chosen baud rate. In LF, max input clock is 32768 (LFXO or LFRCO),
133  *           thus 32768 / 3 ~ 9600 baudrate.
134  ******************************************************************************/
EUSART_UartInitLf(EUSART_TypeDef * eusart,const EUSART_UartInit_TypeDef * init)135 void EUSART_UartInitLf(EUSART_TypeDef *eusart, const EUSART_UartInit_TypeDef *init)
136 {
137   // Make sure the module exists and is Low frequency capable.
138   EFM_ASSERT(EUSART_REF_VALID(eusart) && EUSART_EM2_CAPABLE(EUSART_NUM(eusart)));
139   // Init structure must be provided.
140   EFM_ASSERT(init);
141 
142   // Assert features specific to LF.
143   // LFXO, LFRCO, ULFRCO can be a clock source in LF.
144 #if defined(DEBUG_EFM) || defined(DEBUG_EFM_USER)
145   {
146     CMU_Select_TypeDef clock_source = (CMU_Select_TypeDef) NULL;
147 #if defined(EUART_PRESENT)
148     if (eusart == EUART0) {
149       clock_source = CMU_ClockSelectGet(cmuClock_EUART0);
150     }
151 #endif
152 #if defined(EUSART_PRESENT) && defined(EUSART0)
153     if (eusart == EUSART0) {
154       clock_source = CMU_ClockSelectGet(cmuClock_EUSART0);
155     }
156 #endif
157 
158     EFM_ASSERT(
159       (clock_source == cmuSelect_ULFRCO)
160       || (clock_source == cmuSelect_LFXO)
161       || (clock_source == cmuSelect_LFRCO)
162       || (clock_source == cmuSelect_EM23GRPACLK)
163 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK)
164       || (clock_source == cmuSelect_EM01GRPCCLK)
165 #endif
166 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPACLK)
167       || (clock_source == cmuSelect_EM01GRPACLK) /* ULFRCO, LFXO, LFRCO, EM23GRPACLK, EM01GRPACLK or EM01GRPCCLK */
168 #endif
169       );
170   }
171 #endif
172   // Uart mode only supports up to 9 databits frame.
173   EFM_ASSERT(init->databits <= eusartDataBits9);
174   // The oversampling must be disabled when using a low frequency clock.
175   EFM_ASSERT(init->oversampling == eusartOVS0);
176   // The Majority Vote must be disabled when using a low frequency clock.
177   EFM_ASSERT(init->majorityVote == eusartMajorityVoteDisable);
178   // Number of stop bits can only be 1 or 2 in LF.
179   EFM_ASSERT((init->stopbits == eusartStopbits1) || (init->stopbits == eusartStopbits2));
180   // In LF, max baudrate is 9600. See Note #1.
181   EFM_ASSERT(init->baudrate <= 9600 && init->baudrate != 0);
182 
183   // Initialize EUSART with common features to HF and LF.
184   EUSART_AsyncInitCommon(eusart, init, NULL, NULL);
185 }
186 
187 /***************************************************************************//**
188  * Initializes the EUSART when used in IrDA mode with the high or low
189  * frequency clock.
190  ******************************************************************************/
EUSART_IrDAInit(EUSART_TypeDef * eusart,const EUSART_IrDAInit_TypeDef * irdaInit)191 void EUSART_IrDAInit(EUSART_TypeDef *eusart,
192                      const EUSART_IrDAInit_TypeDef *irdaInit)
193 {
194   // Make sure the module exists on the selected chip.
195   EFM_ASSERT(EUSART_REF_VALID(eusart));
196   // Init structure must be provided.
197   EFM_ASSERT(irdaInit);
198 
199   if (irdaInit->irDALowFrequencyEnable) {
200     // Validate the low frequency capability of the EUSART instance.
201     EFM_ASSERT(EUSART_EM2_CAPABLE(EUSART_NUM(eusart)));
202     // The oversampling must be disabled when using a low frequency clock.
203     EFM_ASSERT(irdaInit->init.oversampling == eusartOVS0);
204     // Number of stop bits can only be 1 or 2 in LF.
205     EFM_ASSERT((irdaInit->init.stopbits == eusartStopbits1) || (irdaInit->init.stopbits == eusartStopbits2));
206     // In LF, max baudrate is 9600. See Note #1.
207     EFM_ASSERT(irdaInit->init.baudrate <= 9600);
208     EFM_ASSERT(irdaInit->init.enable == eusartEnableRx || irdaInit->init.enable == eusartDisable);
209   } else {
210     EFM_ASSERT(irdaInit->init.oversampling != eusartOVS0);
211     // In HF, 2.4 kbps <= baudrate <= 1.152 Mbps.
212     EFM_ASSERT(irdaInit->init.baudrate >= 2400 && irdaInit->init.baudrate <= 1152000);
213   }
214 
215   // Initialize EUSART with common features to HF and LF.
216   EUSART_AsyncInitCommon(eusart, &irdaInit->init, irdaInit, NULL);
217 }
218 
219 #if defined(EUSART_PRESENT)
220 /***************************************************************************//**
221  * Initializes the EUSART when used in SPI mode.
222  ******************************************************************************/
EUSART_SpiInit(EUSART_TypeDef * eusart,EUSART_SpiInit_TypeDef const * init)223 void EUSART_SpiInit(EUSART_TypeDef *eusart, EUSART_SpiInit_TypeDef const *init)
224 {
225   // Make sure the module exists on the selected chip.
226   EFM_ASSERT(EUSART_REF_VALID(eusart));
227   // Init structure must be provided.
228   EFM_ASSERT(init);
229   if (init->master) {
230     EFM_ASSERT(init->bitRate <= 20000000);
231 
232     if (init->advancedSettings) {
233       EFM_ASSERT(!(init->advancedSettings->prsClockEnable));
234     }
235   } else {
236     EFM_ASSERT(init->bitRate <= 10000000);
237     if (init->advancedSettings && init->advancedSettings->forceLoad) {
238       // If baud-rate is more than 5MHz, a value of 4 is recommended, any values
239       // smaller than that can be tried out but avoid using 0. If baud-rate is less than 5MHz,
240       // value of 5 is recommended, values higher than 5 can be used but it may make the load
241       // error easy to occur. The recommended values for frequency bands should be sufficient
242       // to work all the time.
243       EFM_ASSERT((init->bitRate >= 5000000 && init->advancedSettings->setupWindow <= 4)
244                  || (init->bitRate < 5000000 && init->advancedSettings->setupWindow >= 5));
245     }
246   }
247 
248   EUSART_SyncInitCommon(eusart, init);
249 }
250 
251 #if defined(EUSART_DALICFG_DALIEN)
252 /***************************************************************************//**
253  * Initializes the EUSART when used in DALI mode with the high or low
254  * frequency clock.
255  *
256  * @note (1) When EUSART oversampling is set to eusartOVS0 (Disable), the peripheral
257  *           clock frequency must be at least three times higher than the
258  *           chosen baud rate. In LF, max input clock is 32768 (LFXO or LFRCO),
259  *           thus 32768 / 3 ~ 9600 baudrate.
260  ******************************************************************************/
EUSART_DaliInit(EUSART_TypeDef * eusart,const EUSART_DaliInit_TypeDef * daliInit)261 void EUSART_DaliInit(EUSART_TypeDef *eusart,
262                      const EUSART_DaliInit_TypeDef *daliInit)
263 {
264   // Make sure the module exists on the selected chip.
265   EFM_ASSERT(EUSART_REF_VALID(eusart));
266   // Init structure must be provided.
267   EFM_ASSERT(daliInit);
268 
269   if (daliInit->init.loopbackEnable) {
270     // If LOOPBK in CFG0 is set to 1 in order to do loopback testing for DALI,
271     // then in this case DALIRXENDT should be set to 1 and DALIRXDATABITS should
272     // be set the same as DALITXDATABITS.
273     EFM_ASSERT( (daliInit->TXdatabits >> _EUSART_DALICFG_DALITXDATABITS_SHIFT)
274                 == (daliInit->RXdatabits >> _EUSART_DALICFG_DALIRXDATABITS_SHIFT));
275   }
276 
277   if (daliInit->daliLowFrequencyEnable) {
278     // Validate the low frequency capability of the EUSART instance.
279     EFM_ASSERT(EUSART_EM2_CAPABLE(EUSART_NUM(eusart)));
280     // The oversampling must be disabled when using a low frequency clock.
281     EFM_ASSERT(daliInit->init.oversampling == eusartOVS0);
282     // In LF, max baudrate is 9600. See Note #1.
283     // but manchester is running at 2x clock 9600 => 4800
284     EFM_ASSERT(daliInit->init.baudrate <= 4800);
285   } else {
286     EFM_ASSERT(daliInit->init.oversampling != eusartOVS0);
287     // In HF, 2.4 kbps <= baudrate <= 1.152 Mbps.
288     // but manchester is running at 2x clock so 2.4 kbps => 1.2 kbps
289     EFM_ASSERT(daliInit->init.baudrate >= 1200 && daliInit->init.baudrate <= 57600);
290   }
291 
292   // Initialize EUSART with common features to HF and LF.
293   EUSART_AsyncInitCommon(eusart, &daliInit->init, NULL, daliInit);
294 }
295 #endif /* EUSART_DALICFG_DALIEN */
296 #endif /* EUSART_PRESENT */
297 
298 /***************************************************************************//**
299  * Configure the EUSART to its reset state.
300  ******************************************************************************/
EUSART_Reset(EUSART_TypeDef * eusart)301 void EUSART_Reset(EUSART_TypeDef *eusart)
302 {
303   // 1. Properly disable the module
304   EUSART_Disable(eusart);
305 
306 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)  \
307   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4) \
308   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5) \
309   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)
310   // Manual toggling tx_sclk_mst to synchronize handshake
311   // when switching from SPI master to other modes
312   // so module is disabling correctly.
313   uint32_t forcedClkCycle = 4u;
314 
315   while (forcedClkCycle--) {
316     eusart->CFG2_SET = _EUSART_CFG2_CLKPHA_MASK;
317     eusart->CFG2_CLR = _EUSART_CFG2_CLKPHA_MASK;
318   }
319 #endif
320   // All registers that end with CFG should be programmed before EUSART gets enabled (EUSARTn_EN is set).
321   // Set all configurable register to its reset value.
322   // Note: Program desired settings to all registers that have names ending with CFG in the following sequence:
323   //  a. CFG2
324 #if defined(EUSART_PRESENT)
325   eusart->CFG2 = _EUSART_CFG2_RESETVALUE;
326 #endif
327   //  b. CFG1
328   eusart->CFG1 = _EUSART_CFG1_RESETVALUE;
329   //  c. CFG0
330   eusart->CFG0 = _EUSART_CFG0_RESETVALUE;
331   //  d. FRAMECFG, DTXDATCFG, TIMINGCFG (Any sequence)
332   eusart->FRAMECFG = _EUSART_FRAMECFG_RESETVALUE;
333 #if defined(EUSART_PRESENT)
334   eusart->DTXDATCFG = _EUSART_DTXDATCFG_RESETVALUE;
335 #if defined(EUSART_DALICFG_DALIEN)
336   eusart->DALICFG = _EUSART_DALICFG_RESETVALUE;
337 #endif /* EUSART_DALICFG_DALIEN */
338 #endif /* EUSART_PRESENT */
339   eusart->TIMINGCFG = _EUSART_TIMINGCFG_RESETVALUE;
340   eusart->IRHFCFG = _EUSART_IRHFCFG_RESETVALUE;
341   eusart->IRLFCFG = _EUSART_IRLFCFG_RESETVALUE;
342   eusart->STARTFRAMECFG = _EUSART_STARTFRAMECFG_RESETVALUE;
343   eusart->SIGFRAMECFG = _EUSART_SIGFRAMECFG_RESETVALUE;
344   eusart->TRIGCTRL = _EUSART_TRIGCTRL_RESETVALUE;
345   eusart->IEN = _EUSART_IEN_RESETVALUE;
346   eusart->IF_CLR = _EUSART_IF_MASK;
347 
348   // no need to sync while EN=0, multiple writes can be queued up,
349   // and the last one will synchronize once EN=1
350   eusart->CLKDIV = _EUSART_CLKDIV_RESETVALUE;
351 }
352 
353 /***************************************************************************//**
354  * Enables/disables the EUSART receiver and/or transmitter.
355  ******************************************************************************/
EUSART_Enable(EUSART_TypeDef * eusart,EUSART_Enable_TypeDef enable)356 void EUSART_Enable(EUSART_TypeDef *eusart, EUSART_Enable_TypeDef enable)
357 {
358   uint32_t tmp = 0;
359 
360   // Make sure that the module exists on the selected chip.
361   EFM_ASSERT(EUSART_REF_VALID(eusart));
362 
363   if (enable == eusartDisable) {
364     EUSART_Disable(eusart);
365   } else {
366     // Enable peripheral to configure Rx and Tx.
367     eusart->EN_SET = EUSART_EN_EN;
368 
369     // Enable or disable Rx and/or Tx
370     tmp = (enable)
371           & (_EUSART_CMD_RXEN_MASK | _EUSART_CMD_TXEN_MASK
372              | _EUSART_CMD_RXDIS_MASK | _EUSART_CMD_TXDIS_MASK);
373 
374     eusart_sync(eusart, _EUSART_SYNCBUSY_MASK);
375     eusart->CMD = tmp;
376     eusart_sync(eusart,
377                 EUSART_SYNCBUSY_RXEN | EUSART_SYNCBUSY_TXEN
378                 | EUSART_SYNCBUSY_RXDIS | EUSART_SYNCBUSY_TXDIS);
379 
380     // Wait for the status register to be updated.
381     tmp = 0;
382     if (_EUSART_CMD_RXEN_MASK & enable) {
383       tmp |= EUSART_STATUS_RXENS;
384     }
385     if (_EUSART_CMD_TXEN_MASK & enable) {
386       tmp |= EUSART_STATUS_TXENS;
387     }
388     while ((eusart->STATUS & (_EUSART_STATUS_TXENS_MASK | _EUSART_STATUS_RXENS_MASK)) != tmp) {
389     }
390   }
391 }
392 
393 /***************************************************************************//**
394  * Receives one 8 bit frame, (or part of 9 bit frame).
395  *
396  * @note (1) Handles the case where the RX Fifo Watermark has been set to N frames,
397  *       and when N is greater than one. Attempt to read a frame from the RX Fifo.
398  *       If the read is unsuccessful (i.e. no frames in the RX fifo), the RXFU
399  *       interrupt flag is set. If the flag is set, wait to read again until the RXFL
400  *       status flag is set, indicating there are N frames in the RX Fifo, where N
401  *       is equal to the RX watermark level. Once there are N frames in the Fifo,
402  *       read and return one frame. For consecutive N-1 reads there will be data available
403  *       in the Fifo. Therefore, the RXUF interrupt will not be triggered eliminating
404  *       delays between reads and sending N data frames in "bursts".
405  ******************************************************************************/
EUSART_Rx(EUSART_TypeDef * eusart)406 uint8_t EUSART_Rx(EUSART_TypeDef *eusart)
407 {
408   // If RX watermark has not been configured.
409   if ((eusart->CFG1 & _EUSART_CFG1_RXFIW_MASK) == EUSART_CFG1_RXFIW_DEFAULT) {
410     while (!(eusart->STATUS & EUSART_STATUS_RXFL)) {
411     } // Wait for incoming data.
412     return (uint8_t)eusart->RXDATA;
413   }
414 
415   // See Note #1.
416   uint8_t rx_data = eusart->RXDATA;
417   // If there is underflow i.e Rx data read was unsuccessful
418   if (eusart->IF & EUSART_IF_RXUF) {
419     // Wait until data becomes available in Rx fifo
420     while (!(eusart->STATUS & EUSART_STATUS_RXFL)) {
421     }
422     // Read Rx data again once data is available in the fifo
423     rx_data = eusart->RXDATA;
424   }
425 
426   return rx_data;
427 }
428 
429 /***************************************************************************//**
430  * Receives one 8-9 bit frame with extended information.
431  ******************************************************************************/
EUSART_RxExt(EUSART_TypeDef * eusart)432 uint16_t EUSART_RxExt(EUSART_TypeDef *eusart)
433 {
434   while (!(eusart->STATUS & EUSART_STATUS_RXFL)) {
435   } // Wait for incoming data.
436 
437   return (uint16_t)eusart->RXDATA;
438 }
439 
440 /***************************************************************************//**
441  * Transmits one frame.
442  ******************************************************************************/
EUSART_Tx(EUSART_TypeDef * eusart,uint8_t data)443 void EUSART_Tx(EUSART_TypeDef *eusart, uint8_t data)
444 {
445   // Check that transmit FIFO is not full.
446   while (!(eusart->STATUS & EUSART_STATUS_TXFL)) {
447   }
448 
449   eusart->TXDATA = (uint32_t)data;
450 }
451 
452 /***************************************************************************//**
453  * Transmits one 8-9 bit frame with extended control.
454  ******************************************************************************/
EUSART_TxExt(EUSART_TypeDef * eusart,uint16_t data)455 void EUSART_TxExt(EUSART_TypeDef *eusart, uint16_t data)
456 {
457   // Check that transmit FIFO is not full.
458   while (!(eusart->STATUS & EUSART_STATUS_TXFL)) {
459   }
460 
461   eusart->TXDATA = (uint32_t)data;
462 }
463 
464 #if defined(EUSART_PRESENT)
465 /***************************************************************************//**
466  * Transmits one 8-16 bit frame and return received data.
467  ******************************************************************************/
EUSART_Spi_TxRx(EUSART_TypeDef * eusart,uint16_t data)468 uint16_t EUSART_Spi_TxRx(EUSART_TypeDef *eusart, uint16_t data)
469 {
470   // Check that transmit FIFO is not full.
471   while (!(eusart->STATUS & EUSART_STATUS_TXFL)) {
472   }
473   eusart->TXDATA = (uint32_t)data;
474 
475   // Wait for Rx data to be available.
476   while (!(eusart->STATUS & EUSART_STATUS_RXFL)) {
477   }
478   return (uint16_t)eusart->RXDATA;
479 }
480 
481 #if defined(EUSART_DALICFG_DALIEN)
482 /***************************************************************************//**
483  * Transmits one frame.
484  ******************************************************************************/
EUSART_Dali_Tx(EUSART_TypeDef * eusart,uint32_t data)485 void EUSART_Dali_Tx(EUSART_TypeDef *eusart, uint32_t data)
486 {
487   uint32_t packet;
488 
489   // Make sure the module exists on the selected chip.
490   EFM_ASSERT(EUSART_REF_VALID(eusart));
491 
492   // Check that transmit FIFO is not full.
493   while (!(eusart->STATUS & EUSART_STATUS_TXFL)) {
494   }
495 
496   for (uint8_t index = 0; index < dali_tx_nb_packets[EUSART_NUM(eusart)]; index++) {
497     // when DALICFG.DALIEN is set to 1, then all 16 bits [15:0] represent data
498     // First write to TXDATA register should contain 16 LSBs of the TX frame.
499     // Transmission will not start after this first write.
500     // Second write to TXDATA register should contain the remaining TX frame bits.
501     // This second write will result in start of transmission.
502     packet = (data >> (index * 16));
503     // To ensure compatibility with future devices, always write bits [31:16] to 0.
504     packet &= 0x0000FFFF;
505     eusart->TXDATA = packet;
506   }
507 }
508 
509 /***************************************************************************//**
510  * Receive one frame.
511  ******************************************************************************/
EUSART_Dali_Rx(EUSART_TypeDef * eusart)512 uint32_t EUSART_Dali_Rx(EUSART_TypeDef *eusart)
513 {
514   uint32_t data = 0;
515 
516   // Make sure the module exists on the selected chip.
517   EFM_ASSERT(EUSART_REF_VALID(eusart));
518 
519   while (!(eusart->STATUS & EUSART_STATUS_RXFL)) {
520   }   // Wait for incoming data.
521 
522   for (uint8_t index = 0; index < dali_rx_nb_packets[EUSART_NUM(eusart)]; index++) {
523     // when DALICFG.DALIEN is set to 1, then all 16 bits [15:0] represent data
524     // When receiving a frame that has more than 16 databits,
525     // RXDATA register needs to be read twice:
526     //    First read will provide 16 LSBs of the received frame.
527     //    Second read will provide the remaining RX frame bits.
528     data |= ((eusart->RXDATA & _EUSART_RXDATA_RXDATA_MASK) << (index * 16));
529   }
530   return data;
531 }
532 
533 #endif /* EUSART_DALICFG_DALIEN */
534 #endif /* EUSART_PRESENT */
535 
536 /***************************************************************************//**
537  * Configures the baudrate (or as close as possible to a specified baudrate)
538  * depending on the current mode of the EU(S)ART peripheral.
539  *
540  * @note (1) When the oversampling is disabled, the peripheral clock frequency
541  *           must be at least three times higher than the chosen baud rate.
542  ******************************************************************************/
EUSART_BaudrateSet(EUSART_TypeDef * eusart,uint32_t refFreq,uint32_t baudrate)543 void EUSART_BaudrateSet(EUSART_TypeDef *eusart,
544                         uint32_t refFreq,
545                         uint32_t baudrate)
546 {
547   uint32_t          clkdiv;
548   uint8_t           oversample = 0;
549 
550   // Prevent dividing by 0.
551   EFM_ASSERT(baudrate);
552 
553   // Make sure the module exists on the selected chip.
554   EFM_ASSERT(EUSART_REF_VALID(eusart));
555 
556   // Get the current frequency.
557   if (!refFreq) {
558     refFreq = CMU_ClockFreqGet(EUSART_ClockGet(eusart));
559   }
560 
561 #if defined(EUSART_PRESENT)
562   // In synchronous mode (ex: SPI)
563   if (eusart->CFG0 & _EUSART_CFG0_SYNC_MASK ) {
564     EFM_ASSERT(baudrate <= refFreq);
565 
566     EUSART_Enable_TypeDef txrxEnStatus = eusartDisable;
567     bool wasEnabled = (eusart->EN & _EUSART_EN_EN_MASK) == true;
568     clkdiv = refFreq / baudrate - 1UL;
569 
570     // If the desired bit rate requires a divider larger than the Synchronous divider bitfield (CFG2_SDIV),
571     // the resulting spi master bus clock will be undefined because the result will be truncated.
572     EFM_ASSERT(clkdiv <= (_EUSART_CFG2_SDIV_MASK >> _EUSART_CFG2_SDIV_SHIFT));
573 
574     if (wasEnabled) {
575       eusart_sync(eusart, _EUSART_SYNCBUSY_RXEN_MASK | _EUSART_SYNCBUSY_TXEN_MASK);
576 
577       // Save the state of the reveiver and transmitter before disabling the peripheral.
578       if (eusart->STATUS & (_EUSART_STATUS_RXENS_MASK | _EUSART_STATUS_TXENS_MASK)) {
579         txrxEnStatus = eusartEnable;
580       } else if (eusart->STATUS & (_EUSART_STATUS_RXENS_MASK)) {
581         txrxEnStatus = eusartEnableRx;
582       } else if (eusart->STATUS & (_EUSART_STATUS_TXENS_MASK)) {
583         txrxEnStatus = eusartEnableTx;
584       } else {
585         EFM_ASSERT(false);
586       }
587 
588       // Disable the eusart to be able to modify the CFG2 register.
589       EUSART_Disable(eusart);
590     }
591 
592     // In Synchronous mode the clock divider that is managing the bitRate
593     // is located inside the sdiv bitfield of the CFG2 register instead of
594     // the CLKDIV register combined with the oversample setting for asynchronous mode.
595     eusart->CFG2 = (eusart->CFG2 & ~(_EUSART_CFG2_SDIV_MASK)) | ((clkdiv << _EUSART_CFG2_SDIV_SHIFT) & _EUSART_CFG2_SDIV_MASK);
596 
597     if (wasEnabled) {
598       EUSART_Enable(eusart, txrxEnStatus);
599     }
600   } else // In asynchronous mode (ex: UART)
601 #endif
602   {
603     // The peripheral must be enabled to configure the baud rate.
604     EFM_ASSERT(eusart->EN == EUSART_EN_EN);
605 
606 #if defined(EUSART_DALICFG_DALIEN)
607     if (eusart->DALICFG & EUSART_DALICFG_DALIEN) {
608       // adjust for manchester double-clocking scheme
609       baudrate *= 2;
610     }
611 #endif
612 
613     /*
614      * Use integer division to avoid forcing in float division
615      * utils, and yet keep rounding effect errors to a minimum.
616      *
617      * CLKDIV is given by:
618      *
619      * CLKDIV = 256 * (fUARTn/(oversample * br) - 1)
620      * or
621      * CLKDIV = (256 * fUARTn)/(oversample * br) - 256
622      *
623      * Since fUARTn may be derived from HFCORECLK, consider the overflow when
624      * using integer arithmetic.
625      *
626      * The basic problem with integer division in the above formula is that
627      * the dividend (256 * fUARTn) may become higher than the maximum 32 bit
628      * integer. Yet, the dividend should be evaluated first before dividing
629      * to get as small rounding effects as possible.
630      * Also, harsh restrictions on the maximum fUARTn value should not be made.
631      *
632      * Since the last 3 bits of CLKDIV are don't care, base the
633      * integer arithmetic on the below formula:
634      *
635      * CLKDIV/8 = ((32*fUARTn)/(br * Oversample)) - 32
636      *
637      * and calculate 1/8 of CLKDIV first. This allows for fUARTn
638      * up to 128 MHz without overflowing a 32 bit value.
639      */
640 
641     // Map oversampling.
642     switch (eusart->CFG0 & _EUSART_CFG0_OVS_MASK) {
643       case eusartOVS16:
644         EFM_ASSERT(baudrate <= (refFreq / 16));
645         oversample = 16;
646         break;
647 
648       case eusartOVS8:
649         EFM_ASSERT(baudrate <= (refFreq / 8));
650         oversample = 8;
651         break;
652 
653       case eusartOVS6:
654         EFM_ASSERT(baudrate <= (refFreq / 6));
655         oversample = 6;
656         break;
657 
658       case eusartOVS4:
659         EFM_ASSERT(baudrate <= (refFreq / 4));
660         oversample = 4;
661         break;
662 
663       case eusartOVS0:
664         EFM_ASSERT(refFreq >= (3 * baudrate)); // See Note #1.
665         oversample = 1;
666         break;
667 
668       default:
669         // Invalid input
670         EFM_ASSERT(0);
671         break;
672     }
673 
674     if (oversample > 0U) {
675       // Calculate and set the CLKDIV with fractional bits.
676       clkdiv  = (32 * refFreq) / (baudrate * oversample);
677       clkdiv -= 32;
678       clkdiv *= 8;
679 
680       // Verify that the resulting clock divider is within limits.
681       EFM_ASSERT(clkdiv <= _EUSART_CLKDIV_MASK);
682 
683       // If the EFM_ASSERT is not enabled, make sure not to write to reserved bits.
684       clkdiv &= _EUSART_CLKDIV_MASK;
685 
686       eusart_sync(eusart, _EUSART_SYNCBUSY_DIV_MASK);
687       eusart->CLKDIV = clkdiv;
688       eusart_sync(eusart, _EUSART_SYNCBUSY_DIV_MASK);
689     }
690   }
691 }
692 
693 /***************************************************************************//**
694  * Gets the current baudrate.
695  ******************************************************************************/
EUSART_BaudrateGet(EUSART_TypeDef * eusart)696 uint32_t EUSART_BaudrateGet(EUSART_TypeDef *eusart)
697 {
698   uint32_t freq;
699   uint32_t div = 1;
700   uint32_t br = 0;
701   EUSART_OVS_TypeDef ovs = eusartOVS0;
702 
703   // Make sure the module exists on the selected chip.
704   EFM_ASSERT(EUSART_REF_VALID(eusart));
705 
706   freq = CMU_ClockFreqGet(EUSART_ClockGet(eusart));
707 
708 #if defined(EUSART_PRESENT)
709   // In synchronous mode (ex: SPI)
710   if (eusart->CFG0 & _EUSART_CFG0_SYNC_MASK) {
711     div = (eusart->CFG2 & _EUSART_CFG2_SDIV_MASK) >> _EUSART_CFG2_SDIV_SHIFT;
712     br = freq / (div + 1);
713   }
714   // In asynchronous mode (ex: UART)
715   else
716 #endif
717   {
718     div = eusart->CLKDIV;
719     ovs = (EUSART_OVS_TypeDef)(eusart->CFG0 & _EUSART_CFG0_OVS_MASK);
720     br = EUSART_AsyncBaudrateCalc(freq, div, ovs);
721 
722 #if defined(EUSART_DALICFG_DALIEN)
723     if (eusart->DALICFG & EUSART_DALICFG_DALIEN) {
724       // adjust for manchester double-clocking scheme
725       br /= 2;
726     }
727 #endif
728   }
729 
730   return br;
731 }
732 
733 /***************************************************************************//**
734  * Enable/Disable reception operations until the configured start frame is
735  * received.
736  ******************************************************************************/
EUSART_RxBlock(EUSART_TypeDef * eusart,EUSART_BlockRx_TypeDef enable)737 void EUSART_RxBlock(EUSART_TypeDef *eusart, EUSART_BlockRx_TypeDef enable)
738 {
739   uint32_t tmp;
740 
741   // Make sure that the module exists on the selected chip.
742   EFM_ASSERT(EUSART_REF_VALID(eusart));
743 
744   tmp   = ((uint32_t)(enable));
745   tmp  &= (_EUSART_CMD_RXBLOCKEN_MASK | _EUSART_CMD_RXBLOCKDIS_MASK);
746 
747   eusart_sync(eusart, EUSART_SYNCBUSY_RXBLOCKEN | EUSART_SYNCBUSY_RXBLOCKDIS);
748   eusart->CMD_SET = tmp;
749   eusart_sync(eusart, EUSART_SYNCBUSY_RXBLOCKEN | EUSART_SYNCBUSY_RXBLOCKDIS);
750 
751   tmp = 0u;
752   if ((_EUSART_CMD_RXBLOCKEN_MASK & enable) != 0u) {
753     tmp |= EUSART_STATUS_RXBLOCK;
754   }
755   while ((eusart->STATUS & _EUSART_STATUS_RXBLOCK_MASK) != tmp) {
756   } // Wait for the status register to be updated.
757 }
758 
759 /***************************************************************************//**
760  * Enables/Disables the tristating of the transmitter output.
761  ******************************************************************************/
EUSART_TxTristateSet(EUSART_TypeDef * eusart,EUSART_TristateTx_TypeDef enable)762 void  EUSART_TxTristateSet(EUSART_TypeDef *eusart,
763                            EUSART_TristateTx_TypeDef enable)
764 {
765   uint32_t tmp;
766 
767   // Make sure that the module exists on the selected chip.
768   EFM_ASSERT(EUSART_REF_VALID(eusart));
769 
770   tmp   = ((uint32_t)(enable));
771   tmp  &= (_EUSART_CMD_TXTRIEN_MASK | _EUSART_CMD_TXTRIDIS_MASK);
772 
773   eusart_sync(eusart, EUSART_SYNCBUSY_TXTRIEN | EUSART_SYNCBUSY_TXTRIDIS);
774   eusart->CMD = tmp;
775   eusart_sync(eusart, EUSART_SYNCBUSY_TXTRIEN | EUSART_SYNCBUSY_TXTRIDIS);
776 
777   tmp = 0u;
778   if ((_EUSART_CMD_TXTRIEN_MASK & enable) != 0u) {
779     tmp |= EUSART_STATUS_TXTRI;
780   }
781   while ((eusart->STATUS & _EUSART_STATUS_TXTRI_MASK) != tmp) {
782   } // Wait for the status register to be updated.
783 }
784 
785 /***************************************************************************//**
786  * Initializes the automatic enabling of transmissions and/or reception using
787  * the PRS as a trigger.
788  ******************************************************************************/
EUSART_PrsTriggerEnable(EUSART_TypeDef * eusart,const EUSART_PrsTriggerInit_TypeDef * init)789 void EUSART_PrsTriggerEnable(EUSART_TypeDef *eusart,
790                              const EUSART_PrsTriggerInit_TypeDef *init)
791 {
792   uint32_t tmp;
793 
794   // Make sure that the module exists on the selected chip.
795   EFM_ASSERT(EUSART_REF_VALID(eusart));
796 
797   // The peripheral must be enabled to configure the PRS trigger.
798   EFM_ASSERT(eusart->EN == EUSART_EN_EN);
799 
800 #if defined(EUART_PRESENT)
801   PRS->CONSUMER_EUART0_TRIGGER = (init->prs_trigger_channel & _PRS_CONSUMER_EUART0_TRIGGER_MASK);
802 #else
803 
804 #if defined(EUSART0)
805   if (eusart == EUSART0) {
806     PRS->CONSUMER_EUSART0_TRIGGER = (init->prs_trigger_channel & _PRS_CONSUMER_EUSART0_TRIGGER_MASK);
807   }
808 #endif
809 #if defined(EUSART1)
810   if (eusart == EUSART1) {
811     PRS->CONSUMER_EUSART1_TRIGGER = (init->prs_trigger_channel & _PRS_CONSUMER_EUSART1_TRIGGER_MASK);
812   }
813 #endif
814 #if defined(EUSART2)
815   if (eusart == EUSART2) {
816     PRS->CONSUMER_EUSART2_TRIGGER = (init->prs_trigger_channel & _PRS_CONSUMER_EUSART2_TRIGGER_MASK);
817   }
818 #endif
819 #if defined(EUSART3)
820   if (eusart == EUSART3) {
821     PRS->CONSUMER_EUSART3_TRIGGER = (init->prs_trigger_channel & _PRS_CONSUMER_EUSART3_TRIGGER_MASK);
822   }
823 #endif
824 #if defined(EUSART4)
825   if (eusart == EUSART4) {
826     PRS->CONSUMER_EUSART4_TRIGGER = (init->prs_trigger_channel & _PRS_CONSUMER_EUSART4_TRIGGER_MASK);
827   }
828 #endif
829 #endif
830 
831   tmp   = ((uint32_t)(init->prs_trigger_enable));
832   tmp  &= (_EUSART_TRIGCTRL_RXTEN_MASK | _EUSART_TRIGCTRL_TXTEN_MASK);
833 
834   eusart->TRIGCTRL_SET = tmp;
835   eusart_sync(eusart, EUSART_SYNCBUSY_RXTEN | EUSART_SYNCBUSY_TXTEN);
836 
837   tmp   = ~((uint32_t)(init->prs_trigger_enable));
838   tmp  &= (_EUSART_TRIGCTRL_RXTEN_MASK | _EUSART_TRIGCTRL_TXTEN_MASK);
839   eusart->TRIGCTRL_CLR = tmp;
840   eusart_sync(eusart, EUSART_SYNCBUSY_RXTEN | EUSART_SYNCBUSY_TXTEN);
841 }
842 
843 /*******************************************************************************
844  **************************   LOCAL FUNCTIONS   ********************************
845  ******************************************************************************/
846 
847 /***************************************************************************//**
848  * Gets the clock associated to the specified EUSART instance.
849  *
850  * @param eusart Pointer to the EUSART peripheral register block.
851  *
852  * @return Clock corresponding to the eusart.
853  ******************************************************************************/
EUSART_ClockGet(EUSART_TypeDef * eusart)854 static CMU_Clock_TypeDef EUSART_ClockGet(EUSART_TypeDef *eusart)
855 {
856   CMU_Clock_TypeDef clock;
857 
858 #if defined(EUART0)
859   if (eusart == EUART0) {
860     clock = cmuClock_EUART0;
861   }
862 #endif
863 #if defined(EUSART0)
864   if (eusart == EUSART0) {
865     clock = cmuClock_EUSART0;
866   }
867 #endif
868 #if defined(EUSART1)
869   else if (eusart == EUSART1) {
870     clock = cmuClock_EUSART1;
871   }
872 #endif
873 #if defined(EUSART2)
874   else if (eusart == EUSART2) {
875     clock = cmuClock_EUSART2;
876   }
877 #endif
878 #if defined(EUSART3)
879   else if (eusart == EUSART3) {
880     clock = cmuClock_EUSART3;
881   }
882 #endif
883 #if defined(EUSART4)
884   else if (eusart == EUSART4) {
885     clock = cmuClock_EUSART4;
886   }
887 #endif
888   else {
889     EFM_ASSERT(0);
890     return (CMU_Clock_TypeDef)0u;
891   }
892   return clock;
893 }
894 
895 /***************************************************************************//**
896  * Initializes the EUSART with asynchronous common settings to high
897  * and low frequency clock.
898  *
899  * @param eusart Pointer to the EUSART peripheral register block.
900  * @param init A pointer to the initialization structure.
901  * @param irdaInit Pointer to IrDA initialization structure.
902  ******************************************************************************/
EUSART_AsyncInitCommon(EUSART_TypeDef * eusart,const EUSART_UartInit_TypeDef * init,const EUSART_IrDAInit_TypeDef * irdaInit,const EUSART_DaliInit_TypeDef * daliInit)903 static void EUSART_AsyncInitCommon(EUSART_TypeDef *eusart,
904                                    const EUSART_UartInit_TypeDef  *init,
905                                    const EUSART_IrDAInit_TypeDef  *irdaInit,
906                                    const EUSART_DaliInit_TypeDef  *daliInit)
907 {
908   // LF register about to be modified requires sync busy check.
909   if (eusart->EN) {
910     eusart_sync(eusart, _EUSART_SYNCBUSY_MASK);
911   }
912   // Initialize EUSART registers to hardware reset state.
913   EUSART_Reset(eusart);
914 
915   // Configure frame format
916   eusart->FRAMECFG = (eusart->FRAMECFG & ~(_EUSART_FRAMECFG_DATABITS_MASK
917                                            | _EUSART_FRAMECFG_STOPBITS_MASK
918                                            | _EUSART_FRAMECFG_PARITY_MASK))
919                      | (uint32_t)(init->databits)
920                      | (uint32_t)(init->parity)
921                      | (uint32_t)(init->stopbits);
922 
923   // Configure global configuration register 0.
924   eusart->CFG0 = (eusart->CFG0 & ~(_EUSART_CFG0_OVS_MASK
925                                    | _EUSART_CFG0_LOOPBK_MASK
926                                    | _EUSART_CFG0_MVDIS_MASK))
927                  | (uint32_t)(init->oversampling)
928                  | (uint32_t)(init->loopbackEnable)
929                  | (uint32_t)(init->majorityVote);
930 
931   if (init->baudrate == 0) {
932     eusart->CFG0 |= EUSART_CFG0_AUTOBAUDEN;
933   }
934 
935   if (init->advancedSettings) {
936     eusart->CFG0 = (eusart->CFG0 & ~(_EUSART_CFG0_ERRSDMA_MASK | _EUSART_CFG0_AUTOTRI_MASK
937                                      | _EUSART_CFG0_RXINV_MASK | _EUSART_CFG0_TXINV_MASK
938                                      | _EUSART_CFG0_CCEN_MASK  | _EUSART_CFG0_MPM_MASK
939                                      | _EUSART_CFG0_MPAB_MASK  | _EUSART_CFG0_MSBF_MASK))
940                    | (uint32_t)(init->advancedSettings->dmaHaltOnError << _EUSART_CFG0_ERRSDMA_SHIFT)
941                    | (uint32_t)(init->advancedSettings->txAutoTristate << _EUSART_CFG0_AUTOTRI_SHIFT)
942                    | (uint32_t)(init->advancedSettings->invertIO & (_EUSART_CFG0_RXINV_MASK | _EUSART_CFG0_TXINV_MASK))
943                    | (uint32_t)(init->advancedSettings->collisionDetectEnable << _EUSART_CFG0_CCEN_SHIFT)
944                    | (uint32_t)(init->advancedSettings->multiProcessorEnable << _EUSART_CFG0_MPM_SHIFT)
945                    | (uint32_t)(init->advancedSettings->multiProcessorAddressBitHigh << _EUSART_CFG0_MPAB_SHIFT)
946                    | (uint32_t)(init->advancedSettings->msbFirst << _EUSART_CFG0_MSBF_SHIFT);
947 
948     // Configure global configuration register 1.
949     eusart->CFG1 = (eusart->CFG1 & ~(_EUSART_CFG1_RXFIW_MASK | _EUSART_CFG1_TXFIW_MASK
950                                      | _EUSART_CFG1_RXDMAWU_MASK | _EUSART_CFG1_TXDMAWU_MASK))
951                    | (uint32_t)(init->advancedSettings->RxFifoWatermark)
952                    | (uint32_t)(init->advancedSettings->TxFifoWatermark)
953                    | (uint32_t)(init->advancedSettings->dmaWakeUpOnRx << _EUSART_CFG1_RXDMAWU_SHIFT)
954                    | (uint32_t)(init->advancedSettings->dmaWakeUpOnTx << _EUSART_CFG1_TXDMAWU_SHIFT);
955 
956     if (init->advancedSettings->hwFlowControl == eusartHwFlowControlCts
957         || init->advancedSettings->hwFlowControl == eusartHwFlowControlCtsAndRts) {
958       eusart->CFG1 |= EUSART_CFG1_CTSEN;
959     }
960     // Enable RTS route pin if necessary. CTS is an input so it is enabled by default.
961     if ((init->advancedSettings->hwFlowControl == eusartHwFlowControlRts)
962         || (init->advancedSettings->hwFlowControl == eusartHwFlowControlCtsAndRts)) {
963 #if defined(EUART0)
964       GPIO->EUARTROUTE_SET->ROUTEEN = GPIO_EUART_ROUTEEN_RTSPEN;
965 #elif defined(EUSART0)
966       GPIO->EUSARTROUTE_SET[EUSART_NUM(eusart)].ROUTEEN = GPIO_EUSART_ROUTEEN_RTSPEN;
967 #endif
968     } else {
969 #if defined(EUART0)
970       GPIO->EUARTROUTE_CLR->ROUTEEN = GPIO_EUART_ROUTEEN_RTSPEN;
971 #elif defined(EUSART0)
972       GPIO->EUSARTROUTE_CLR[EUSART_NUM(eusart)].ROUTEEN = GPIO_EUSART_ROUTEEN_RTSPEN;
973 #endif
974     }
975     eusart->STARTFRAMECFG_SET = (uint32_t)init->advancedSettings->startFrame;
976     if (init->advancedSettings->startFrame) {
977       eusart->CFG1 |= EUSART_CFG1_SFUBRX;
978     }
979     if (init->advancedSettings->prsRxEnable) {
980       eusart->CFG1 |= EUSART_CFG1_RXPRSEN;
981       // Configure PRS channel as input data line for EUSART.
982 #if defined(EUART_PRESENT)
983       PRS->CONSUMER_EUART0_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUART0_RX_MASK);
984 #elif defined(EUSART_PRESENT)
985 
986       if (eusart == EUSART0) {
987         PRS->CONSUMER_EUSART0_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART0_RX_MASK);
988       }
989 #if defined(EUSART1)
990       if (eusart == EUSART1) {
991         PRS->CONSUMER_EUSART1_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART1_RX_MASK);
992       }
993 #endif
994 #if defined(EUSART2)
995       if (eusart == EUSART2) {
996         PRS->CONSUMER_EUSART2_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART2_RX_MASK);
997       }
998 #endif
999 #if defined(EUSART3)
1000       if (eusart == EUSART3) {
1001         PRS->CONSUMER_EUSART3_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART3_RX_MASK);
1002       }
1003 #endif
1004 #if defined(EUSART4)
1005       if (eusart == EUSART4) {
1006         PRS->CONSUMER_EUSART4_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART4_RX_MASK);
1007       }
1008 #endif
1009 #endif
1010     }
1011 
1012     // Configure global configuration timing register.
1013     eusart->TIMINGCFG = (eusart->TIMINGCFG & ~_EUSART_TIMINGCFG_TXDELAY_MASK)
1014                         | (uint32_t)(init->advancedSettings->autoTxDelay);
1015   }
1016 
1017   if (irdaInit) {
1018     if (irdaInit->irDALowFrequencyEnable) {
1019       eusart->IRLFCFG_SET = (uint32_t)(EUSART_IRLFCFG_IRLFEN);
1020     } else {
1021       // Configure IrDA HF configuration register.
1022       eusart->IRHFCFG_SET = (eusart->IRHFCFG & ~(_EUSART_IRHFCFG_IRHFEN_MASK
1023                                                  | _EUSART_IRHFCFG_IRHFEN_MASK
1024                                                  | _EUSART_IRHFCFG_IRHFFILT_MASK))
1025                             | (uint32_t)(EUSART_IRHFCFG_IRHFEN)
1026                             | (uint32_t)(irdaInit->irDAPulseWidth)
1027                             | (uint32_t)(irdaInit->irDARxFilterEnable);
1028     }
1029   }
1030 
1031 #if defined(EUSART_DALICFG_DALIEN)
1032   // DALI-specific configuration section
1033   if (daliInit) {
1034     if (init->loopbackEnable) {
1035       // If LOOPBK in CFG0 is set to 1 in order to do loopback testing for DALI,
1036       // then in this case DALIRXENDT should be set to 1.
1037       eusart->DALICFG_SET = EUSART_DALICFG_DALIRXENDT;
1038     }
1039 
1040     if (EUSART_REF_VALID(eusart)) {
1041       uint8_t index = EUSART_NUM(eusart);
1042 
1043       // keep track of the number of 16-bits packet to send
1044       if (daliInit->TXdatabits <= eusartDaliTxDataBits16) {
1045         dali_tx_nb_packets[index] = 1;
1046       } else {
1047         dali_tx_nb_packets[index] = 2;
1048       }
1049 
1050       // keep track of the number of 16-bits packet to receive
1051       if (daliInit->RXdatabits <= eusartDaliRxDataBits16) {
1052         dali_rx_nb_packets[index] = 1;
1053       } else {
1054         dali_rx_nb_packets[index] = 2;
1055       }
1056     }
1057 
1058     // Configure the numbers of bits per TX and RX frames
1059     eusart->DALICFG = (eusart->DALICFG & ~(_EUSART_DALICFG_DALITXDATABITS_MASK
1060                                            | _EUSART_DALICFG_DALIRXDATABITS_MASK))
1061                       | daliInit->TXdatabits
1062                       | daliInit->RXdatabits;
1063     eusart->DALICFG_SET = EUSART_DALICFG_DALIEN;
1064   }
1065 #else
1066   (void)(daliInit);
1067 #endif /* EUSART_DALICFG_DALIEN */
1068 
1069   // Enable EUSART IP.
1070   EUSART_Enable(eusart, eusartEnable);
1071 
1072   // Configure the baudrate if auto baud detection is not used.
1073   if (init->baudrate) {
1074     EUSART_BaudrateSet(eusart, init->refFreq, init->baudrate);
1075   }
1076 
1077   // Finally enable the Rx and/or Tx channel (as specified).
1078   EUSART_Enable(eusart, init->enable);
1079   while (~EUSART_StatusGet(eusart) & (_EUSART_STATUS_RXIDLE_MASK | _EUSART_STATUS_TXIDLE_MASK)) {
1080   }
1081 }
1082 
1083 #if defined(EUSART_PRESENT)
1084 /***************************************************************************//**
1085  * Initializes the EUSART with synchronous common settings to high
1086  * and low frequency clock.
1087  *
1088  * @param eusart Pointer to the EUSART peripheral register block.
1089  * @param init A pointer to the initialization structure.
1090  ******************************************************************************/
EUSART_SyncInitCommon(EUSART_TypeDef * eusart,EUSART_SpiInit_TypeDef const * init)1091 static void EUSART_SyncInitCommon(EUSART_TypeDef *eusart,
1092                                   EUSART_SpiInit_TypeDef const *init)
1093 {
1094   void* advancedSetting_ptr = (void*)init->advancedSettings; // Used to avoid GCC over optimization.
1095 
1096   // LF register about to be modified requires sync busy check.
1097   if (eusart->EN) {
1098     eusart_sync(eusart, _EUSART_SYNCBUSY_MASK);
1099   }
1100 
1101   // Initialize EUSART registers to hardware reset state.
1102   EUSART_Reset(eusart);
1103 
1104   // Configure global configuration register 2.
1105   eusart->CFG2 = (eusart->CFG2 & ~(_EUSART_CFG2_MASTER_MASK
1106                                    | _EUSART_CFG2_CLKPOL_MASK
1107                                    | _EUSART_CFG2_CLKPHA_MASK
1108                                    | _EUSART_CFG2_FORCELOAD_MASK))
1109                  | (uint32_t)(init->master)
1110                  | (uint32_t)(init->clockMode)
1111                  | (uint32_t)(EUSART_CFG2_FORCELOAD); // Force load feature enabled by default.
1112 
1113   if (advancedSetting_ptr) {
1114     // Configure global configuration register 2.
1115     eusart->CFG2 = (eusart->CFG2 & ~(_EUSART_CFG2_FORCELOAD_MASK
1116                                      | _EUSART_CFG2_AUTOCS_MASK
1117                                      | _EUSART_CFG2_AUTOTX_MASK
1118                                      | _EUSART_CFG2_CSINV_MASK
1119                                      | _EUSART_CFG2_CLKPRSEN_MASK))
1120                    | (uint32_t)(init->advancedSettings->forceLoad << _EUSART_CFG2_FORCELOAD_SHIFT)
1121                    | (uint32_t)(init->advancedSettings->autoCsEnable << _EUSART_CFG2_AUTOCS_SHIFT)
1122                    | (uint32_t)(init->advancedSettings->autoTxEnable << _EUSART_CFG2_AUTOTX_SHIFT)
1123                    | (uint32_t)(init->advancedSettings->csPolarity)
1124                    | (uint32_t)(init->advancedSettings->prsClockEnable << _EUSART_CFG2_CLKPRSEN_SHIFT);
1125 
1126     // Only applicable to EM2 (low frequency) capable EUSART instances.
1127     eusart->CFG1 = (eusart->CFG1 & ~(_EUSART_CFG1_RXFIW_MASK
1128                                      | _EUSART_CFG1_TXFIW_MASK))
1129                    | (uint32_t)(init->advancedSettings->RxFifoWatermark)
1130                    | (uint32_t)(init->advancedSettings->TxFifoWatermark)
1131                    | (uint32_t)(init->advancedSettings->dmaWakeUpOnRx << _EUSART_CFG1_RXDMAWU_SHIFT)
1132                    | (uint32_t)(init->advancedSettings->prsRxEnable << _EUSART_CFG1_RXPRSEN_SHIFT);
1133   }
1134 
1135   eusart->CFG0 = (eusart->CFG0 & ~(_EUSART_CFG0_SYNC_MASK
1136                                    | _EUSART_CFG0_LOOPBK_MASK))
1137                  | (uint32_t)(_EUSART_CFG0_SYNC_SYNC)
1138                  | (uint32_t)(init->loopbackEnable);
1139 
1140   if (advancedSetting_ptr) {
1141     eusart->CFG0 |= (uint32_t)init->advancedSettings->invertIO & (_EUSART_CFG0_RXINV_MASK | _EUSART_CFG0_TXINV_MASK);
1142     eusart->CFG0 |= (uint32_t)init->advancedSettings->msbFirst << _EUSART_CFG0_MSBF_SHIFT;
1143 
1144     // Configure global configurationTiming register.
1145     eusart->TIMINGCFG = (eusart->TIMINGCFG & ~(_EUSART_TIMINGCFG_CSSETUP_MASK
1146                                                | _EUSART_TIMINGCFG_CSHOLD_MASK
1147                                                | _EUSART_TIMINGCFG_ICS_MASK
1148                                                | _EUSART_TIMINGCFG_SETUPWINDOW_MASK))
1149                         | ((uint32_t)(init->advancedSettings->autoCsSetupTime << _EUSART_TIMINGCFG_CSSETUP_SHIFT)
1150                            & _EUSART_TIMINGCFG_CSSETUP_MASK)
1151                         | ((uint32_t)(init->advancedSettings->autoCsHoldTime << _EUSART_TIMINGCFG_CSHOLD_SHIFT)
1152                            & _EUSART_TIMINGCFG_CSHOLD_MASK)
1153                         | ((uint32_t)(init->advancedSettings->autoInterFrameTime << _EUSART_TIMINGCFG_ICS_SHIFT)
1154                            & _EUSART_TIMINGCFG_ICS_MASK)
1155                         | ((uint32_t)(init->advancedSettings->setupWindow << _EUSART_TIMINGCFG_SETUPWINDOW_SHIFT)
1156                            & _EUSART_TIMINGCFG_SETUPWINDOW_MASK)
1157     ;
1158   }
1159 
1160   // Configure frame format
1161   eusart->FRAMECFG = (eusart->FRAMECFG & ~(_EUSART_FRAMECFG_DATABITS_MASK))
1162                      | (uint32_t)(init->databits);
1163 
1164   if (advancedSetting_ptr) {
1165     eusart->DTXDATCFG = (init->advancedSettings->defaultTxData & _EUSART_DTXDATCFG_MASK);
1166 
1167     if (init->advancedSettings->prsRxEnable) {
1168       //Configure PRS channel as input data line for EUSART.
1169       if (eusart == EUSART0) {
1170         PRS->CONSUMER_EUSART0_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART0_RX_MASK);
1171       }
1172 #if defined(EUSART1)
1173       if (eusart == EUSART1) {
1174         PRS->CONSUMER_EUSART1_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART1_RX_MASK);
1175       }
1176 #endif
1177 #if defined(EUSART2)
1178       if (eusart == EUSART2) {
1179         PRS->CONSUMER_EUSART2_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART2_RX_MASK);
1180       }
1181 #endif
1182 #if defined(EUSART3)
1183       if (eusart == EUSART3) {
1184         PRS->CONSUMER_EUSART3_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART3_RX_MASK);
1185       }
1186 #endif
1187 #if defined(EUSART4)
1188       if (eusart == EUSART4) {
1189         PRS->CONSUMER_EUSART4_RX_SET = (init->advancedSettings->prsRxChannel & _PRS_CONSUMER_EUSART4_RX_MASK);
1190       }
1191 #endif
1192     }
1193 
1194     if (init->advancedSettings->prsClockEnable) {
1195       //Configure PRS channel as SCLK input for EUSART.
1196       if (eusart == EUSART0) {
1197         PRS->CONSUMER_EUSART0_CLK_SET = (init->advancedSettings->prsClockChannel & _PRS_CONSUMER_EUSART0_CLK_MASK);
1198       }
1199 #if defined(EUSART1)
1200       if (eusart == EUSART1) {
1201         PRS->CONSUMER_EUSART1_CLK_SET = (init->advancedSettings->prsClockChannel & _PRS_CONSUMER_EUSART1_CLK_MASK);
1202       }
1203 #endif
1204 #if defined(EUSART2)
1205       if (eusart == EUSART2) {
1206         PRS->CONSUMER_EUSART2_CLK_SET = (init->advancedSettings->prsClockChannel & _PRS_CONSUMER_EUSART2_CLK_MASK);
1207       }
1208 #endif
1209 #if defined(EUSART3)
1210       if (eusart == EUSART3) {
1211         PRS->CONSUMER_EUSART3_CLK_SET = (init->advancedSettings->prsClockChannel & _PRS_CONSUMER_EUSART3_CLK_MASK);
1212       }
1213 #endif
1214 #if defined(EUSART4)
1215       if (eusart == EUSART4) {
1216         PRS->CONSUMER_EUSART4_CLK_SET = (init->advancedSettings->prsClockChannel & _PRS_CONSUMER_EUSART4_CLK_MASK);
1217       }
1218 #endif
1219     }
1220   }
1221 
1222   // Set baudrate for synchronous operation mode.
1223   EUSART_BaudrateSet(eusart, init->refFreq, init->bitRate);
1224 
1225   // Enable EUSART IP.
1226   EUSART_Enable(eusart, eusartEnable);
1227 
1228   // Finally enable the Rx and/or Tx channel (as specified).
1229   eusart_sync(eusart, _EUSART_SYNCBUSY_RXEN_MASK | _EUSART_SYNCBUSY_TXEN_MASK); // Wait for low frequency register synchronization.
1230   eusart->CMD = (uint32_t)init->enable;
1231   eusart_sync(eusart, _EUSART_SYNCBUSY_RXEN_MASK | _EUSART_SYNCBUSY_TXEN_MASK);
1232   while (~EUSART_StatusGet(eusart) & (_EUSART_STATUS_RXIDLE_MASK | _EUSART_STATUS_TXIDLE_MASK)) {
1233   }
1234 }
1235 #endif
1236 
1237 /***************************************************************************//**
1238  * Calculate baudrate for a given reference frequency, clock division,
1239  * and oversampling rate when the module is in UART mode.
1240  *
1241  * @param refFreq The EUSART reference clock frequency in Hz that will be used.
1242  * @param clkdiv Clock division factor to be used.
1243  * @param ovs Oversampling to be used.
1244  *
1245  * @return Computed baudrate from given settings.
1246  ******************************************************************************/
EUSART_AsyncBaudrateCalc(uint32_t refFreq,uint32_t clkdiv,EUSART_OVS_TypeDef ovs)1247 __STATIC_INLINE uint32_t EUSART_AsyncBaudrateCalc(uint32_t refFreq,
1248                                                   uint32_t clkdiv,
1249                                                   EUSART_OVS_TypeDef ovs)
1250 {
1251   uint32_t oversample;
1252   uint64_t divisor;
1253   uint64_t factor;
1254   uint64_t remainder;
1255   uint64_t quotient;
1256   uint32_t br;
1257 
1258   // Out of bound clkdiv.
1259   EFM_ASSERT(clkdiv <= _EUSART_CLKDIV_MASK);
1260 
1261   // Mask out unused bits
1262   clkdiv &= _EUSART_CLKDIV_MASK;
1263 
1264   /* Use integer division to avoid forcing in float division
1265    * utils and yet keep rounding effect errors to a minimum.
1266    *
1267    * Baudrate in is given by:
1268    *
1269    * br = fUARTn/(oversample * (1 + (CLKDIV / 256)))
1270    * or
1271    * br = (256 * fUARTn)/(oversample * (256 + CLKDIV))
1272    *
1273    * 256 factor of the dividend is reduced with a
1274    * (part of) oversample part of the divisor.
1275    */
1276 
1277   switch (ovs) {
1278     case eusartOVS16:
1279       oversample = 1;
1280       factor = 256 / 16;
1281       break;
1282 
1283     case eusartOVS8:
1284       oversample = 1;
1285       factor = 256 / 8;
1286       break;
1287 
1288     case eusartOVS6:
1289       oversample = 3;
1290       factor = 256 / 2;
1291       break;
1292 
1293     case eusartOVS4:
1294       oversample = 1;
1295       factor = 256 / 4;
1296       break;
1297 
1298     case eusartOVS0:
1299       oversample = 1;
1300       factor = 256;
1301       break;
1302 
1303     default:
1304       return 0u;
1305       break;
1306   }
1307 
1308   /*
1309    * The basic problem with integer division in the above formula is that
1310    * the dividend (factor * fUARTn) may become larger than a 32 bit
1311    * integer. Yet we want to evaluate the dividend first before dividing
1312    * to get as small rounding effects as possible. Too harsh restrictions
1313    * should not be made on the maximum fUARTn value either.
1314    *
1315    * For division a/b,
1316    *
1317    * a = qb + r
1318    *
1319    * where q is the quotient and r is the remainder, both integers.
1320    *
1321    * The original baudrate formula can be rewritten as
1322    *
1323    * br = xa / b = x(qb + r)/b = xq + xr/b
1324    *
1325    * where x is 'factor', a is 'refFreq' and b is 'divisor', referring to
1326    * variable names.
1327    */
1328 
1329   /*
1330    * The divisor will never exceed max 32 bit value since
1331    * clkdiv <= _EUSART_CLKDIV_MASK (currently 0x7FFFF8)
1332    * and 'oversample' has been reduced to <= 3.
1333    */
1334   divisor = (uint64_t)(oversample * (256 + clkdiv));
1335 
1336   quotient = refFreq / divisor;
1337   remainder = refFreq % divisor;
1338 
1339   // The factor <= 128 and since divisor >= 256, the below cannot exceed the maximum
1340   // 32 bit value. However, factor * remainder can become larger than 32-bit
1341   // because of the size of _EUSART_CLKDIV_DIV_MASK on some families.
1342   br = (uint32_t) (factor * quotient);
1343 
1344   /*
1345    * The factor <= 128 and remainder < (oversample*(256 + clkdiv)), which
1346    * means dividend (factor * remainder) worst case is
1347    * 128 * (3 * (256 + _EUSART_CLKDIV_MASK)) = 0xC001_7400.
1348    */
1349   br += (uint32_t) ((factor * remainder) / divisor);
1350 
1351   return br;
1352 }
1353 
1354 /***************************************************************************//**
1355  * Perform EUSART Module disablement - resetting all internal flops/FSM.
1356  *
1357  * @param eusart Pointer to the EUSART peripheral register block.
1358  ******************************************************************************/
EUSART_Disable(EUSART_TypeDef * eusart)1359 __STATIC_INLINE void EUSART_Disable(EUSART_TypeDef *eusart)
1360 {
1361   if (eusart->EN & _EUSART_EN_EN_MASK) {
1362     // This step should be skipped especially in Synchronous Slave mode when
1363     // external SCLK is not running and CS is active
1364 #if defined(EUSART_PRESENT)
1365     if (!(eusart->CFG0 & _EUSART_CFG0_SYNC_MASK) || (eusart->CFG2 & _EUSART_CFG2_MASTER_MASK))
1366 #endif
1367     {
1368       // General Programming Guideline to properly disable the module:
1369       // 1a. Disable TX and RX using TXDIS and RXDIS cmd
1370       eusart->CMD = EUSART_CMD_TXDIS | EUSART_CMD_RXDIS;
1371       // 1b. Poll for EUSARTn_SYNCBUSY.TXDIS and EUSARTn_SYNCBUSY.RXDIS to go low;
1372       eusart_sync(eusart, (EUSART_SYNCBUSY_TXDIS | EUSART_SYNCBUSY_RXDIS));
1373       // 1c. Wait for EUSARTn_STATUS.TXENS and EUSARTn_STATUS.RXENS to go low
1374       while (eusart->STATUS & (_EUSART_STATUS_TXENS_MASK | _EUSART_STATUS_RXENS_MASK)) {
1375       }
1376     }
1377 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1378     eusart->CLKDIV = eusart->CLKDIV;
1379     eusart_sync(eusart, _EUSART_SYNCBUSY_DIV_MASK);
1380 
1381     // Read data until FIFO is emptied
1382     // but taking care not to underflow the receiver
1383     while (eusart->STATUS & EUSART_STATUS_RXFL) {
1384       eusart->RXDATA;
1385     }
1386 #endif
1387 
1388     eusart->EN_CLR = EUSART_EN_EN;
1389 
1390 #if defined(_EUSART_EN_DISABLING_MASK)
1391     // 2. Polling for EUSARTn_EN.DISABLING = 0.
1392     while (eusart->EN & _EUSART_EN_DISABLING_MASK) {
1393     }
1394 #endif
1395   }
1396 }
1397 
1398 #endif /* defined(EUART_PRESENT) || defined(EUSART_PRESENT) */
1399