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