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