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