1 /******************************************************************************
2 * Filename: uart.c
3 *
4 * Description: Driver for the UART.
5 *
6 * Copyright (c) 2015 - 2022, Texas Instruments Incorporated
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * 1) Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * 2) Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 ******************************************************************************/
36
37 #include "uart.h"
38
39 //*****************************************************************************
40 //
41 // Handle support for DriverLib in ROM:
42 // This section will undo prototype renaming made in the header file
43 //
44 //*****************************************************************************
45 #if !defined(DOXYGEN)
46 #undef UARTFIFOLevelGet
47 #define UARTFIFOLevelGet NOROM_UARTFIFOLevelGet
48 #undef UARTConfigSetExpClk
49 #define UARTConfigSetExpClk NOROM_UARTConfigSetExpClk
50 #undef UARTConfigGetExpClk
51 #define UARTConfigGetExpClk NOROM_UARTConfigGetExpClk
52 #undef UARTDisable
53 #define UARTDisable NOROM_UARTDisable
54 #undef UARTCharGetNonBlocking
55 #define UARTCharGetNonBlocking NOROM_UARTCharGetNonBlocking
56 #undef UARTCharGet
57 #define UARTCharGet NOROM_UARTCharGet
58 #undef UARTCharPutNonBlocking
59 #define UARTCharPutNonBlocking NOROM_UARTCharPutNonBlocking
60 #undef UARTCharPut
61 #define UARTCharPut NOROM_UARTCharPut
62 #undef UARTIntRegister
63 #define UARTIntRegister NOROM_UARTIntRegister
64 #undef UARTIntUnregister
65 #define UARTIntUnregister NOROM_UARTIntUnregister
66 #endif
67
68 //*****************************************************************************
69 //
70 // Gets the FIFO level at which interrupts are generated
71 //
72 //*****************************************************************************
73 void
UARTFIFOLevelGet(uint32_t ui32Base,uint32_t * pui32TxLevel,uint32_t * pui32RxLevel)74 UARTFIFOLevelGet(uint32_t ui32Base, uint32_t *pui32TxLevel,
75 uint32_t *pui32RxLevel)
76 {
77 uint32_t ui32Temp;
78
79 // Check the arguments.
80 ASSERT(UARTBaseValid(ui32Base));
81
82 // Read the FIFO level register.
83 ui32Temp = HWREG(ui32Base + UART_O_IFLS);
84
85 // Extract the transmit and receive FIFO levels.
86 *pui32TxLevel = ui32Temp & UART_IFLS_TXSEL_M;
87 *pui32RxLevel = ui32Temp & UART_IFLS_RXSEL_M;
88 }
89
90 //*****************************************************************************
91 //
92 // Sets the configuration of a UART
93 //
94 //*****************************************************************************
95 void
UARTConfigSetExpClk(uint32_t ui32Base,uint32_t ui32UARTClk,uint32_t ui32Baud,uint32_t ui32Config)96 UARTConfigSetExpClk(uint32_t ui32Base, uint32_t ui32UARTClk,
97 uint32_t ui32Baud, uint32_t ui32Config)
98 {
99 uint32_t ui32Div;
100
101 // Check the arguments.
102 ASSERT(UARTBaseValid(ui32Base));
103 ASSERT(ui32Baud != 0);
104
105 // Stop the UART.
106 UARTDisable(ui32Base);
107
108 // Compute the fractional baud rate divider.
109 ui32Div = (((ui32UARTClk * 8) / ui32Baud) + 1) / 2;
110
111 // Set the baud rate.
112 HWREG(ui32Base + UART_O_IBRD) = ui32Div / 64;
113 HWREG(ui32Base + UART_O_FBRD) = ui32Div % 64;
114
115 // Set parity, data length, and number of stop bits.
116 HWREG(ui32Base + UART_O_LCRH) = ui32Config;
117 }
118
119 //*****************************************************************************
120 //
121 // Gets the current configuration of a UART
122 //
123 //*****************************************************************************
124 void
UARTConfigGetExpClk(uint32_t ui32Base,uint32_t ui32UARTClk,uint32_t * pui32Baud,uint32_t * pui32Config)125 UARTConfigGetExpClk(uint32_t ui32Base, uint32_t ui32UARTClk,
126 uint32_t *pui32Baud, uint32_t *pui32Config)
127 {
128 uint32_t ui32Int, ui32Frac;
129
130 // Check the arguments.
131 ASSERT(UARTBaseValid(ui32Base));
132
133 // Compute the baud rate.
134 ui32Int = HWREG(ui32Base + UART_O_IBRD);
135 ui32Frac = HWREG(ui32Base + UART_O_FBRD);
136 *pui32Baud = (ui32UARTClk * 4) / ((64 * ui32Int) + ui32Frac);
137
138 // Get the parity, data length, and number of stop bits.
139 *pui32Config = (HWREG(ui32Base + UART_O_LCRH) &
140 (UART_LCRH_SPS | UART_LCRH_WLEN_M | UART_LCRH_STP2 |
141 UART_LCRH_EPS | UART_LCRH_PEN));
142 }
143
144 //*****************************************************************************
145 //
146 // Disables transmitting and receiving
147 //
148 //*****************************************************************************
149 void
UARTDisable(uint32_t ui32Base)150 UARTDisable(uint32_t ui32Base)
151 {
152
153 // Check the arguments.
154 ASSERT(UARTBaseValid(ui32Base));
155
156 // Wait for end of TX.
157 while(HWREG(ui32Base + UART_O_FR) & UART_FR_BUSY)
158 {
159 }
160
161 // Disable the FIFO.
162 HWREG(ui32Base + UART_O_LCRH) &= ~(UART_LCRH_FEN);
163
164 // Disable the UART.
165 HWREG(ui32Base + UART_O_CTL) &= ~(UART_CTL_UARTEN | UART_CTL_TXE |
166 UART_CTL_RXE);
167 }
168
169 //*****************************************************************************
170 //
171 // Receives a character from the specified port
172 //
173 //*****************************************************************************
174 int32_t
UARTCharGetNonBlocking(uint32_t ui32Base)175 UARTCharGetNonBlocking(uint32_t ui32Base)
176 {
177 // Check the arguments.
178 ASSERT(UARTBaseValid(ui32Base));
179
180 // See if there are any characters in the receive FIFO.
181 if(!(HWREG(ui32Base + UART_O_FR) & UART_FR_RXFE))
182 {
183 // Read and return the next character.
184 return(HWREG(ui32Base + UART_O_DR));
185 }
186 else
187 {
188 // There are no characters, so return a failure.
189 return(-1);
190 }
191 }
192
193 //*****************************************************************************
194 //
195 // Waits for a character from the specified port
196 //
197 //*****************************************************************************
198 int32_t
UARTCharGet(uint32_t ui32Base)199 UARTCharGet(uint32_t ui32Base)
200 {
201 // Check the arguments.
202 ASSERT(UARTBaseValid(ui32Base));
203
204 // Wait until a char is available.
205 while(HWREG(ui32Base + UART_O_FR) & UART_FR_RXFE)
206 {
207 }
208
209 // Now get the character.
210 return(HWREG(ui32Base + UART_O_DR));
211 }
212
213 //*****************************************************************************
214 //
215 // Sends a character to the specified port
216 //
217 //*****************************************************************************
218 bool
UARTCharPutNonBlocking(uint32_t ui32Base,uint8_t ui8Data)219 UARTCharPutNonBlocking(uint32_t ui32Base, uint8_t ui8Data)
220 {
221 // Check the arguments.
222 ASSERT(UARTBaseValid(ui32Base));
223
224 // See if there is space in the transmit FIFO.
225 if(!(HWREG(ui32Base + UART_O_FR) & UART_FR_TXFF))
226 {
227 // Write this character to the transmit FIFO.
228 HWREG(ui32Base + UART_O_DR) = ui8Data;
229
230 // Success.
231 return(true);
232 }
233 else
234 {
235 // There is no space in the transmit FIFO, so return a failure.
236 return(false);
237 }
238 }
239
240 //*****************************************************************************
241 //
242 // Waits to send a character from the specified port
243 //
244 //*****************************************************************************
245 void
UARTCharPut(uint32_t ui32Base,uint8_t ui8Data)246 UARTCharPut(uint32_t ui32Base, uint8_t ui8Data)
247 {
248 // Check the arguments.
249 ASSERT(UARTBaseValid(ui32Base));
250
251 // Wait until space is available.
252 while(HWREG(ui32Base + UART_O_FR) & UART_FR_TXFF)
253 {
254 }
255
256 // Send the char.
257 HWREG(ui32Base + UART_O_DR) = ui8Data;
258 }
259
260 //*****************************************************************************
261 //
262 // Registers an interrupt handler for a UART interrupt
263 //
264 //*****************************************************************************
265 void
UARTIntRegister(uint32_t ui32Base,void (* pfnHandler)(void))266 UARTIntRegister(uint32_t ui32Base, void (*pfnHandler)(void))
267 {
268 // Check the arguments.
269 ASSERT(UARTBaseValid(ui32Base));
270
271 // Register and enable the interrupt handler.
272 // (Doing the '& 0xFFFF' to catch both buffered and unbuffered offsets)
273 if (( ui32Base & 0xFFFF ) == ( UART0_BASE & 0xFFFF ))
274 {
275 IntRegister(INT_UART0_COMB, pfnHandler);
276 IntEnable(INT_UART0_COMB);
277 }
278 else
279 {
280 IntRegister(INT_UART1_COMB, pfnHandler);
281 IntEnable(INT_UART1_COMB);
282 }
283 }
284
285 //*****************************************************************************
286 //
287 // Unregisters an interrupt handler for a UART interrupt
288 //
289 //*****************************************************************************
290 void
UARTIntUnregister(uint32_t ui32Base)291 UARTIntUnregister(uint32_t ui32Base)
292 {
293 // Check the arguments.
294 ASSERT(UARTBaseValid(ui32Base));
295
296 // Disable and unregister the interrupt.
297 // (Doing the '& 0xFFFF' to catch both buffered and unbuffered offsets)
298 if (( ui32Base & 0xFFFF ) == ( UART0_BASE & 0xFFFF ))
299 {
300 IntDisable(INT_UART0_COMB);
301 IntUnregister(INT_UART0_COMB);
302 }
303 else
304 {
305 IntDisable(INT_UART1_COMB);
306 IntUnregister(INT_UART1_COMB);
307 }
308 }
309