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