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