1 /***************************************************************************//**
2 * @file
3 * @brief Low Energy Universal Asynchronous Receiver/Transmitter (LEUART)
4 * peripheral API
5 *******************************************************************************
6 * # License
7 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
8 *******************************************************************************
9 *
10 * SPDX-License-Identifier: Zlib
11 *
12 * The licensor of this software is Silicon Laboratories Inc.
13 *
14 * This software is provided 'as-is', without any express or implied
15 * warranty. In no event will the authors be held liable for any damages
16 * arising from the use of this software.
17 *
18 * Permission is granted to anyone to use this software for any purpose,
19 * including commercial applications, and to alter it and redistribute it
20 * freely, subject to the following restrictions:
21 *
22 * 1. The origin of this software must not be misrepresented; you must not
23 * claim that you wrote the original software. If you use this software
24 * in a product, an acknowledgment in the product documentation would be
25 * appreciated but is not required.
26 * 2. Altered source versions must be plainly marked as such, and must not be
27 * misrepresented as being the original software.
28 * 3. This notice may not be removed or altered from any source distribution.
29 *
30 ******************************************************************************/
31
32 #ifndef EM_LEUART_H
33 #define EM_LEUART_H
34
35 #include "em_device.h"
36 #if defined(LEUART_COUNT) && (LEUART_COUNT > 0)
37
38 #include <stdbool.h>
39
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43
44 /***************************************************************************//**
45 * @addtogroup leuart
46 * @{
47 ******************************************************************************/
48
49 /*******************************************************************************
50 ******************************** ENUMS ************************************
51 ******************************************************************************/
52
53 /** Data bit selection. */
54 typedef enum {
55 leuartDatabits8 = LEUART_CTRL_DATABITS_EIGHT, /**< 8 data bits. */
56 leuartDatabits9 = LEUART_CTRL_DATABITS_NINE /**< 9 data bits. */
57 } LEUART_Databits_TypeDef;
58
59 /** Enable selection. */
60 typedef enum {
61 /** Disable both receiver and transmitter. */
62 leuartDisable = 0x0,
63
64 /** Enable receiver only, transmitter disabled. */
65 leuartEnableRx = LEUART_CMD_RXEN,
66
67 /** Enable transmitter only, receiver disabled. */
68 leuartEnableTx = LEUART_CMD_TXEN,
69
70 /** Enable both receiver and transmitter. */
71 leuartEnable = (LEUART_CMD_RXEN | LEUART_CMD_TXEN)
72 } LEUART_Enable_TypeDef;
73
74 /** Parity selection. */
75 typedef enum {
76 leuartNoParity = LEUART_CTRL_PARITY_NONE, /**< No parity. */
77 leuartEvenParity = LEUART_CTRL_PARITY_EVEN, /**< Even parity. */
78 leuartOddParity = LEUART_CTRL_PARITY_ODD /**< Odd parity. */
79 } LEUART_Parity_TypeDef;
80
81 /** Stop bits selection. */
82 typedef enum {
83 leuartStopbits1 = LEUART_CTRL_STOPBITS_ONE, /**< 1 stop bits. */
84 leuartStopbits2 = LEUART_CTRL_STOPBITS_TWO /**< 2 stop bits. */
85 } LEUART_Stopbits_TypeDef;
86
87 /*******************************************************************************
88 ******************************* STRUCTS ***********************************
89 ******************************************************************************/
90
91 /** Initialization structure. */
92 typedef struct {
93 /** Specifies whether TX and/or RX will be enabled when initialization completes. */
94 LEUART_Enable_TypeDef enable;
95
96 /**
97 * LEUART reference clock assumed when configuring baud rate setup. Set
98 * to 0 if using currently configured reference clock.
99 */
100 uint32_t refFreq;
101
102 /** Desired baud rate. */
103 uint32_t baudrate;
104
105 /** Number of data bits in frame. */
106 LEUART_Databits_TypeDef databits;
107
108 /** Parity mode to use. */
109 LEUART_Parity_TypeDef parity;
110
111 /** Number of stop bits to use. */
112 LEUART_Stopbits_TypeDef stopbits;
113 } LEUART_Init_TypeDef;
114
115 /** Default configuration for LEUART initialization structure. */
116 #define LEUART_INIT_DEFAULT \
117 { \
118 leuartEnable, /* Enable RX/TX when initialization completed. */ \
119 0, /* Use current configured reference clock for configuring baud rate.*/ \
120 9600, /* 9600 bits/s. */ \
121 leuartDatabits8, /* 8 data bits. */ \
122 leuartNoParity, /* No parity. */ \
123 leuartStopbits1 /* 1 stop bit. */ \
124 }
125
126 /*******************************************************************************
127 ***************************** PROTOTYPES **********************************
128 ******************************************************************************/
129
130 uint32_t LEUART_BaudrateCalc(uint32_t refFreq, uint32_t clkdiv);
131 uint32_t LEUART_BaudrateGet(LEUART_TypeDef *leuart);
132 void LEUART_BaudrateSet(LEUART_TypeDef *leuart,
133 uint32_t refFreq,
134 uint32_t baudrate);
135 void LEUART_Enable(LEUART_TypeDef *leuart, LEUART_Enable_TypeDef enable);
136 void LEUART_FreezeEnable(LEUART_TypeDef *leuart, bool enable);
137 void LEUART_Init(LEUART_TypeDef *leuart, LEUART_Init_TypeDef const *init);
138 void LEUART_TxDmaInEM2Enable(LEUART_TypeDef *leuart, bool enable);
139 void LEUART_RxDmaInEM2Enable(LEUART_TypeDef *leuart, bool enable);
140
141 /***************************************************************************//**
142 * @brief
143 * Clear one or more pending LEUART interrupts.
144 *
145 * @param[in] leuart
146 * Pointer to LEUART peripheral register block.
147 *
148 * @param[in] flags
149 * Pending LEUART interrupt source to clear. Use a bitwise logic OR
150 * combination of valid interrupt flags for LEUART module (LEUART_IF_nnn).
151 ******************************************************************************/
LEUART_IntClear(LEUART_TypeDef * leuart,uint32_t flags)152 __STATIC_INLINE void LEUART_IntClear(LEUART_TypeDef *leuart, uint32_t flags)
153 {
154 leuart->IFC = flags;
155 }
156
157 /***************************************************************************//**
158 * @brief
159 * Disable one or more LEUART interrupts.
160 *
161 * @param[in] leuart
162 * Pointer to LEUART peripheral register block.
163 *
164 * @param[in] flags
165 * LEUART interrupt sources to disable. Use a bitwise logic OR combination of
166 * valid interrupt flags for LEUART module (LEUART_IF_nnn).
167 ******************************************************************************/
LEUART_IntDisable(LEUART_TypeDef * leuart,uint32_t flags)168 __STATIC_INLINE void LEUART_IntDisable(LEUART_TypeDef *leuart, uint32_t flags)
169 {
170 leuart->IEN &= ~flags;
171 }
172
173 /***************************************************************************//**
174 * @brief
175 * Enable one or more LEUART interrupts.
176 *
177 * @note
178 * Depending on the use, a pending interrupt may already be set prior to
179 * enabling the interrupt. To ignore a pending interrupt, consider using
180 * LEUART_IntClear() prior to enabling the interrupt.
181 *
182 * @param[in] leuart
183 * Pointer to LEUART peripheral register block.
184 *
185 * @param[in] flags
186 * LEUART interrupt sources to enable. Use a bitwise logic OR combination of
187 * valid interrupt flags for LEUART module (LEUART_IF_nnn).
188 ******************************************************************************/
LEUART_IntEnable(LEUART_TypeDef * leuart,uint32_t flags)189 __STATIC_INLINE void LEUART_IntEnable(LEUART_TypeDef *leuart, uint32_t flags)
190 {
191 leuart->IEN |= flags;
192 }
193
194 /***************************************************************************//**
195 * @brief
196 * Get pending LEUART interrupt flags.
197 *
198 * @note
199 * The event bits are not cleared by the use of this function.
200 *
201 * @param[in] leuart
202 * Pointer to LEUART peripheral register block.
203 *
204 * @return
205 * LEUART interrupt sources pending. A bitwise logic OR combination of valid
206 * interrupt flags for LEUART module (LEUART_IF_nnn).
207 ******************************************************************************/
LEUART_IntGet(LEUART_TypeDef * leuart)208 __STATIC_INLINE uint32_t LEUART_IntGet(LEUART_TypeDef *leuart)
209 {
210 return leuart->IF;
211 }
212
213 /***************************************************************************//**
214 * @brief
215 * Get enabled and pending LEUART interrupt flags.
216 * Useful for handling more interrupt sources in the same interrupt handler.
217 *
218 * @param[in] leuart
219 * Pointer to LEUART peripheral register block.
220 *
221 * @note
222 * Interrupt flags are not cleared by the use of this function.
223 *
224 * @return
225 * Pending and enabled LEUART interrupt sources.
226 * The return value is the bitwise AND combination of
227 * - the OR combination of enabled interrupt sources in LEUARTx_IEN_nnn
228 * register (LEUARTx_IEN_nnn) and
229 * - the OR combination of valid interrupt flags of LEUART module
230 * (LEUARTx_IF_nnn).
231 ******************************************************************************/
LEUART_IntGetEnabled(LEUART_TypeDef * leuart)232 __STATIC_INLINE uint32_t LEUART_IntGetEnabled(LEUART_TypeDef *leuart)
233 {
234 uint32_t tmp;
235
236 /* Store LEUARTx->IEN in temporary variable in order to define explicit order
237 * of volatile accesses. */
238 tmp = leuart->IEN;
239
240 /* Bitwise AND of pending and enabled interrupts */
241 return leuart->IF & tmp;
242 }
243
244 /***************************************************************************//**
245 * @brief
246 * Set one or more pending LEUART interrupts from SW.
247 *
248 * @param[in] leuart
249 * Pointer to LEUART peripheral register block.
250 *
251 * @param[in] flags
252 * LEUART interrupt sources to set to pending. Use a bitwise logic OR
253 * combination of valid interrupt flags for LEUART module (LEUART_IF_nnn).
254 ******************************************************************************/
LEUART_IntSet(LEUART_TypeDef * leuart,uint32_t flags)255 __STATIC_INLINE void LEUART_IntSet(LEUART_TypeDef *leuart, uint32_t flags)
256 {
257 leuart->IFS = flags;
258 }
259
260 /***************************************************************************//**
261 * @brief
262 * Get LEUART STATUS register.
263 *
264 * @param[in] leuart
265 * Pointer to LEUART peripheral register block.
266 *
267 * @return
268 * STATUS register value.
269 *
270 ******************************************************************************/
LEUART_StatusGet(LEUART_TypeDef * leuart)271 __STATIC_INLINE uint32_t LEUART_StatusGet(LEUART_TypeDef *leuart)
272 {
273 return leuart->STATUS;
274 }
275
276 void LEUART_Reset(LEUART_TypeDef *leuart);
277 uint8_t LEUART_Rx(LEUART_TypeDef *leuart);
278 uint16_t LEUART_RxExt(LEUART_TypeDef *leuart);
279 void LEUART_Tx(LEUART_TypeDef *leuart, uint8_t data);
280 void LEUART_TxExt(LEUART_TypeDef *leuart, uint16_t data);
281
282 /***************************************************************************//**
283 * @brief
284 * Receive one 8 bit frame, (or part of a 9 bit frame).
285 *
286 * @details
287 * Used to quickly receive one 8 bit frame by reading RXDATA register
288 * directly, without checking STATUS register for RXDATAV flag.
289 * This can be useful from RXDATAV interrupt handler, i.e., waiting
290 * is superfluous, in order to quickly read received data.
291 * Please refer to @ref LEUART_RxDataXGet() for reception of 9 bit frames.
292 *
293 * @note
294 * Since this function does not check if the RXDATA register actually
295 * holds valid data, it should only be used in situations when it is certain
296 * that there is valid data, ensured by some external program routine, e.g.,
297 * when handling an RXDATAV interrupt. The @ref LEUART_Rx() is normally a
298 * better choice if the validity of the RXDATA register is not certain.
299 *
300 * @note
301 * Notice that possible parity/stop bits are not
302 * considered part of specified frame bit length.
303 *
304 * @param[in] leuart
305 * Pointer to LEUART peripheral register block.
306 *
307 * @return
308 * Data received.
309 ******************************************************************************/
LEUART_RxDataGet(LEUART_TypeDef * leuart)310 __STATIC_INLINE uint8_t LEUART_RxDataGet(LEUART_TypeDef *leuart)
311 {
312 return (uint8_t)leuart->RXDATA;
313 }
314
315 /***************************************************************************//**
316 * @brief
317 * Receive one 8-9 bit frame, with extended information.
318 *
319 * @details
320 * Used to quickly receive one 8-9 bit frame with extended information
321 * by reading RXDATAX register directly, without checking STATUS
322 * register for RXDATAV flag. This can be useful from RXDATAV
323 * interrupt handler, i.e., waiting is superfluous, in order to quickly
324 * read received data.
325 *
326 * @note
327 * Since this function does not check if the RXDATAX register actually
328 * holds valid data, it should only be used in situations when it is certain
329 * that there is valid data, ensured by some external program routine, e.g.,
330 * when handling an RXDATAV interrupt. The @ref LEUART_RxExt() is normally
331 * a better choice if the validity of the RXDATAX register is not certain.
332 *
333 * @note
334 * Notice that possible parity/stop bits are not
335 * considered part of specified frame bit length.
336 *
337 * @param[in] leuart
338 * Pointer to LEUART peripheral register block.
339 *
340 * @return
341 * Data received.
342 ******************************************************************************/
LEUART_RxDataXGet(LEUART_TypeDef * leuart)343 __STATIC_INLINE uint16_t LEUART_RxDataXGet(LEUART_TypeDef *leuart)
344 {
345 return (uint16_t)leuart->RXDATAX;
346 }
347
348 /** @} (end addtogroup leuart) */
349
350 #ifdef __cplusplus
351 }
352 #endif
353
354 #endif /* defined(LEUART_COUNT) && (LEUART_COUNT > 0) */
355 #endif /* EM_LEUART_H */
356