1 //*****************************************************************************
2 //
3 //  am_hal_uart.c
4 //! @file
5 //!
6 //! @brief Functions for interfacing with the UART.
7 //!
8 //! @addtogroup uart2 UART
9 //! @ingroup apollo2hal
10 //! @{
11 //
12 //*****************************************************************************
13 
14 //*****************************************************************************
15 //
16 // Copyright (c) 2017, Ambiq Micro
17 // All rights reserved.
18 //
19 // Redistribution and use in source and binary forms, with or without
20 // modification, are permitted provided that the following conditions are met:
21 //
22 // 1. Redistributions of source code must retain the above copyright notice,
23 // this list of conditions and the following disclaimer.
24 //
25 // 2. Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // 3. Neither the name of the copyright holder nor the names of its
30 // contributors may be used to endorse or promote products derived from this
31 // software without specific prior written permission.
32 //
33 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
37 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 // POSSIBILITY OF SUCH DAMAGE.
44 //
45 // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
46 //
47 //*****************************************************************************
48 
49 #include <stdint.h>
50 #include <stdbool.h>
51 #include "am_mcu_apollo.h"
52 
53 //*****************************************************************************
54 //
55 // Transmit and receive queue pointers for each UART module.
56 //
57 //*****************************************************************************
58 am_hal_queue_t g_psTxQueue[AM_REG_UART_NUM_MODULES];
59 am_hal_queue_t g_psRxQueue[AM_REG_UART_NUM_MODULES];
60 
61 //*****************************************************************************
62 //
63 // Power tracking structure
64 //
65 //*****************************************************************************
66 am_hal_uart_pwrsave_t am_hal_uart_pwrsave[AM_REG_UART_NUM_MODULES];
67 
68 //*****************************************************************************
69 //
70 // Set Baud Rate based on the UART clock frequency.
71 //
72 //*****************************************************************************
73 
74 #define BAUDCLK     (32)
75 
76 static void
config_baudrate(uint32_t ui32Module,uint32_t ui32Baudrate,uint32_t ui32UartClkFreq)77 config_baudrate(uint32_t ui32Module, uint32_t ui32Baudrate, uint32_t ui32UartClkFreq)
78 {
79     uint64_t ui64FractionDivisorLong;
80     uint64_t ui64IntermediateLong;
81     uint32_t ui32IntegerDivisor;
82     uint32_t ui32FractionDivisor;
83     uint32_t ui32BaudClk;
84 
85     //
86     // Calculate register values.
87     //
88     ui32BaudClk = BAUDCLK * ui32Baudrate;
89     ui32IntegerDivisor = (uint32_t)(ui32UartClkFreq / ui32BaudClk);
90     ui64IntermediateLong = (ui32UartClkFreq * 64) / ui32BaudClk;
91     ui64FractionDivisorLong = ui64IntermediateLong - (ui32IntegerDivisor * 64);
92     ui32FractionDivisor = (uint32_t)ui64FractionDivisorLong;
93 
94     //
95     // Check the result.
96     //
97     am_hal_debug_assert_msg(ui32IntegerDivisor > 0, "Integer divisor MUST be greater than or equal to 1.");
98 
99     //
100     // Write the UART regs.
101     //
102     AM_REGn(UART, ui32Module, IBRD) = ui32IntegerDivisor;
103     AM_REGn(UART, ui32Module, IBRD) = ui32IntegerDivisor;
104     AM_REGn(UART, ui32Module, FBRD) = ui32FractionDivisor;
105 }
106 
107 //*****************************************************************************
108 //
109 //! @brief Set up the UART.
110 //!
111 //! @param psConfig pointer to a structure that holds the settings for the UART.
112 //! @param ui32UartclkFreq is clock frequency that the UART is running at.
113 //!
114 //! This function should be used to perform the initial set-up of the UART.
115 //!
116 //! @return none.
117 //
118 //*****************************************************************************
119 void
am_hal_uart_config(uint32_t ui32Module,am_hal_uart_config_t * psConfig)120 am_hal_uart_config(uint32_t ui32Module, am_hal_uart_config_t *psConfig)
121 
122 {
123     uint32_t ui32ConfigVal = 0;
124 
125     //
126     // Configure the Baudrate.
127     //
128     config_baudrate(ui32Module, psConfig->ui32BaudRate, am_hal_clkgen_sysclk_get());
129 
130     //
131     // OR in the Data bits.
132     //
133     ui32ConfigVal |= psConfig->ui32DataBits;
134 
135     //
136     // OR in the Two Stop bit if used.
137     //
138     ui32ConfigVal |= psConfig->bTwoStopBits ? AM_REG_UART_LCRH_STP2_M : 0;
139 
140     //
141     // OR in the Parity.
142     //
143     ui32ConfigVal |= psConfig->ui32Parity;
144 
145     //
146     // Write config to Line control register.
147     //
148     AM_REGn(UART, ui32Module, LCRH) |= ui32ConfigVal;
149 
150     //
151     // Write the flow control settings to the control register.
152     //
153     AM_REGn(UART, ui32Module, CR) |= psConfig->ui32FlowCtrl;
154 
155     //
156     // Set the clock select field for 24MHz from the HFRC
157     //
158     AM_REGn(UART, ui32Module, CR) |= AM_REG_UART_CR_CLKSEL_24MHZ;
159 }
160 
161 //*****************************************************************************
162 //
163 //! @brief Gets the status.
164 //!
165 //! This function returns the current status.
166 //!
167 //! @return current status.
168 //
169 //*****************************************************************************
170 uint32_t
am_hal_uart_status_get(uint32_t ui32Module)171 am_hal_uart_status_get(uint32_t ui32Module)
172 {
173     //
174     // Read and return the Status.
175     //
176     return AM_REGn(UART, ui32Module, RSR);
177 }
178 
179 //*****************************************************************************
180 //
181 //! @brief Gets the interrupt status.
182 //!
183 //! @param bEnabledOnly - If true returns the enabled interrupt status.
184 //!
185 //! This function returns the masked or raw interrupt status.
186 //!
187 //! @return Bitwise representation of the current interrupt status.
188 //!
189 //! The return value will be the logical OR of one or more of the following
190 //! values:
191 //!
192 //!     AM_HAL_UART_INT_OVER_RUN
193 //!     AM_HAL_UART_INT_BREAK_ERR
194 //!     AM_HAL_UART_INT_PARITY_ERR
195 //!     AM_HAL_UART_INT_FRAME_ERR
196 //!     AM_HAL_UART_INT_RX_TMOUT
197 //!     AM_HAL_UART_INT_TX
198 //!     AM_REG_UART_IER_TXIM_M
199 //!     AM_HAL_UART_INT_RX
200 //!     AM_HAL_UART_INT_DSRM
201 //!     AM_HAL_UART_INT_DCDM
202 //!     AM_HAL_UART_INT_CTSM
203 //!     AM_HAL_UART_INT_RIM
204 //
205 //*****************************************************************************
206 uint32_t
am_hal_uart_int_status_get(uint32_t ui32Module,bool bEnabledOnly)207 am_hal_uart_int_status_get(uint32_t ui32Module, bool bEnabledOnly)
208 {
209     if (bEnabledOnly)
210     {
211         //
212         // Read and return the Masked Interrupt Status.
213         //
214         return AM_REGn(UART, ui32Module, MIS);
215     }
216     else
217     {
218         //
219         // Read and return the Raw Interrupt Status.
220         //
221         return AM_REGn(UART, ui32Module, IES);
222     }
223 }
224 
225 //*****************************************************************************
226 //
227 //! @brief Clears the desired interrupts.
228 //!
229 //! @param ui32Interrupt - Interrupt bits to clear.
230 //!
231 //! This function clears the desired interrupts.
232 //!
233 //! ui32Interrupt should be a logical or of the following:
234 //!
235 //!     AM_HAL_UART_INT_OVER_RUN
236 //!     AM_HAL_UART_INT_BREAK_ERR
237 //!     AM_HAL_UART_INT_PARITY_ERR
238 //!     AM_HAL_UART_INT_FRAME_ERR
239 //!     AM_HAL_UART_INT_RX_TMOUT
240 //!     AM_HAL_UART_INT_TX
241 //!     AM_REG_UART_IER_TXIM_M
242 //!     AM_HAL_UART_INT_RX
243 //!     AM_HAL_UART_INT_DSRM
244 //!     AM_HAL_UART_INT_DCDM
245 //!     AM_HAL_UART_INT_CTSM
246 //!     AM_HAL_UART_INT_RIM
247 //!
248 //! @return None.
249 //
250 //*****************************************************************************
251 void
am_hal_uart_int_clear(uint32_t ui32Module,uint32_t ui32Interrupt)252 am_hal_uart_int_clear(uint32_t ui32Module, uint32_t ui32Interrupt)
253 {
254     //
255     // Clear the bits.
256     //
257     AM_REGn(UART, ui32Module, IEC) = ui32Interrupt;
258 }
259 
260 //*****************************************************************************
261 //
262 //! @brief Disables the desired interrupts.
263 //!
264 //! @param ui32Interrupt - Interrupt bits to disable.
265 //!
266 //! This function disables the desired interrupts.
267 //!
268 //! ui32Interrupt should be a logical or of the following:
269 //!
270 //!     AM_HAL_UART_INT_OVER_RUN
271 //!     AM_HAL_UART_INT_BREAK_ERR
272 //!     AM_HAL_UART_INT_PARITY_ERR
273 //!     AM_HAL_UART_INT_FRAME_ERR
274 //!     AM_HAL_UART_INT_RX_TMOUT
275 //!     AM_HAL_UART_INT_TX
276 //!     AM_REG_UART_IER_TXIM_M
277 //!     AM_HAL_UART_INT_RX
278 //!     AM_HAL_UART_INT_DSRM
279 //!     AM_HAL_UART_INT_DCDM
280 //!     AM_HAL_UART_INT_CTSM
281 //!     AM_HAL_UART_INT_RIM
282 //!
283 //! @return None.
284 //
285 //*****************************************************************************
286 void
am_hal_uart_int_disable(uint32_t ui32Module,uint32_t ui32Interrupt)287 am_hal_uart_int_disable(uint32_t ui32Module, uint32_t ui32Interrupt)
288 {
289     //
290     // Disable the bits.
291     //
292     AM_REGn(UART, ui32Module, IER) &= ~ui32Interrupt;
293 }
294 
295 //*****************************************************************************
296 //
297 //! @brief Enables the desired interrupts.
298 //!
299 //! @param ui32Interrupt - Interrupt bits to enable.
300 //!
301 //! This function enables the desired interrupts.
302 //!
303 //! ui32Interrupt should be a logical or of the following:
304 //!
305 //!     AM_HAL_UART_INT_OVER_RUN
306 //!     AM_HAL_UART_INT_BREAK_ERR
307 //!     AM_HAL_UART_INT_PARITY_ERR
308 //!     AM_HAL_UART_INT_FRAME_ERR
309 //!     AM_HAL_UART_INT_RX_TMOUT
310 //!     AM_HAL_UART_INT_TX
311 //!     AM_REG_UART_IER_TXIM_M
312 //!     AM_HAL_UART_INT_RX
313 //!     AM_HAL_UART_INT_DSRM
314 //!     AM_HAL_UART_INT_DCDM
315 //!     AM_HAL_UART_INT_CTSM
316 //!     AM_HAL_UART_INT_RIM
317 //!
318 //! @return None.
319 //
320 //*****************************************************************************
321 void
am_hal_uart_int_enable(uint32_t ui32Module,uint32_t ui32Interrupt)322 am_hal_uart_int_enable(uint32_t ui32Module, uint32_t ui32Interrupt)
323 {
324     //
325     // Enable the interrupts.
326     //
327     AM_REGn(UART, ui32Module, IER) |= ui32Interrupt;
328 }
329 
330 //*****************************************************************************
331 //
332 //! @brief Returns the enabled interrupts.
333 //!
334 //! This function return the enabled interrupts.
335 //!
336 //! @return the enabled interrupts. This will be a logical or of the following:
337 //!
338 //!     AM_HAL_UART_INT_OVER_RUN
339 //!     AM_HAL_UART_INT_BREAK_ERR
340 //!     AM_HAL_UART_INT_PARITY_ERR
341 //!     AM_HAL_UART_INT_FRAME_ERR
342 //!     AM_HAL_UART_INT_RX_TMOUT
343 //!     AM_HAL_UART_INT_TX
344 //!     AM_REG_UART_IER_TXIM_M
345 //!     AM_HAL_UART_INT_RX
346 //!     AM_HAL_UART_INT_DSRM
347 //!     AM_HAL_UART_INT_DCDM
348 //!     AM_HAL_UART_INT_CTSM
349 //!     AM_HAL_UART_INT_RIM
350 //!
351 //! @return Returns the enabled interrupts.
352 //
353 //*****************************************************************************
354 uint32_t
am_hal_uart_int_enable_get(uint32_t ui32Module)355 am_hal_uart_int_enable_get(uint32_t ui32Module)
356 {
357     //
358     // Return the enabled interrupts.
359     //
360     return AM_REGn(UART, ui32Module, IER);
361 }
362 
363 //*****************************************************************************
364 //
365 //! @brief Enable the UART, RX, and TX.
366 //!
367 //! This function enables the UART, RX, and TX.
368 //!
369 //! @return None.
370 //
371 //*****************************************************************************
372 void
am_hal_uart_enable(uint32_t ui32Module)373 am_hal_uart_enable(uint32_t ui32Module)
374 {
375     //
376     // Enable the UART, RX, and TX.
377     //
378     AM_REGan_SET(UART, ui32Module, CR, (AM_REG_UART_CR_UARTEN_M   |
379                                         AM_REG_UART_CR_RXE_M      |
380                                         AM_REG_UART_CR_TXE_M) );
381 }
382 
383 //*****************************************************************************
384 //
385 //! @brief Disable the UART, RX, and TX.
386 //!
387 //! This function disables the UART, RX, and TX.
388 //!
389 //! @return None.
390 //
391 //*****************************************************************************
392 void
am_hal_uart_disable(uint32_t ui32Module)393 am_hal_uart_disable(uint32_t ui32Module)
394 {
395     //
396     // Disable the UART.
397     //
398     AM_REGan_CLR(UART, ui32Module, CR, (AM_REG_UART_CR_UARTEN_M   |
399                                         AM_REG_UART_CR_RXE_M      |
400                                         AM_REG_UART_CR_TXE_M) );
401 }
402 
403 //*****************************************************************************
404 //
405 //! @brief Enable the UART in the power control block.
406 //!
407 //! This function enables the UART device in the power control block.
408 //!
409 //! @return None.
410 //
411 //*****************************************************************************
412 void
am_hal_uart_pwrctrl_enable(uint32_t ui32Module)413 am_hal_uart_pwrctrl_enable(uint32_t ui32Module)
414 {
415     //
416     // Check to make sure we're acting on a real UART module.
417     //
418     am_hal_debug_assert_msg(ui32Module < AM_REG_UART_NUM_MODULES,
419                             "Trying to disable a UART module that doesn't exist");
420 
421     am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_UART0 << ui32Module);
422 }
423 
424 //*****************************************************************************
425 //
426 //! @brief Disable the UART in the power control block.
427 //!
428 //! This function disables the UART device in the power control block.
429 //!
430 //! @return None.
431 //
432 //*****************************************************************************
433 void
am_hal_uart_pwrctrl_disable(uint32_t ui32Module)434 am_hal_uart_pwrctrl_disable(uint32_t ui32Module)
435 {
436     //
437     // Check to make sure we're acting on a real UART module.
438     //
439     am_hal_debug_assert_msg(ui32Module < AM_REG_UART_NUM_MODULES,
440                             "Trying to disable a UART module that doesn't exist");
441 
442     am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_UART0 << ui32Module);
443 }
444 
445 //*****************************************************************************
446 //
447 //! @brief Enable the UART in the power control block.
448 //!
449 //! This function enables the UART device in the power control block.
450 //!
451 //! @return None.
452 //
453 //*****************************************************************************
454 void
am_hal_uart_power_on_restore(uint32_t ui32Module)455 am_hal_uart_power_on_restore(uint32_t ui32Module)
456 {
457     //
458     // Check to make sure we're acting on a real UART module.
459     //
460     am_hal_debug_assert_msg(ui32Module < AM_REG_UART_NUM_MODULES,
461                             "Trying to enable a UART module that doesn't exist");
462 
463     //
464     // Make sure this restore is a companion to a previous save call.
465     //
466     if ( am_hal_uart_pwrsave[ui32Module].bValid == 0 )
467     {
468         return;
469     }
470 
471     //
472     // Enable power to the selected UART
473     //
474     am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_UART0 << ui32Module);
475 
476     //
477     // Restore the clock settings
478     //
479     am_hal_clkgen_uarten_set(ui32Module, am_hal_uart_pwrsave[ui32Module].UARTEN);
480 
481     //
482     // Restore the configuration registers from the global variable in SRAM.
483     //
484     AM_REGn(UART, ui32Module, ILPR) = am_hal_uart_pwrsave[ui32Module].ILPR;
485     AM_REGn(UART, ui32Module, IBRD) = am_hal_uart_pwrsave[ui32Module].IBRD;
486     AM_REGn(UART, ui32Module, FBRD) = am_hal_uart_pwrsave[ui32Module].FBRD;
487     AM_REGn(UART, ui32Module, LCRH) = am_hal_uart_pwrsave[ui32Module].LCRH;
488     AM_REGn(UART, ui32Module, CR)   = am_hal_uart_pwrsave[ui32Module].CR;
489     AM_REGn(UART, ui32Module, IFLS) = am_hal_uart_pwrsave[ui32Module].IFLS;
490     AM_REGn(UART, ui32Module, IER)  = am_hal_uart_pwrsave[ui32Module].IER;
491 
492     //
493     // Indicates we have restored the configuration.
494     //
495     am_hal_uart_pwrsave[ui32Module].bValid = 0;
496 
497     return;
498 }
499 
500 //*****************************************************************************
501 //
502 //! @brief Disable the UART in the power control block.
503 //!
504 //! This function disables the UART device in the power control block.
505 //!
506 //! @return None.
507 //
508 //*****************************************************************************
509 void
am_hal_uart_power_off_save(uint32_t ui32Module)510 am_hal_uart_power_off_save(uint32_t ui32Module)
511 {
512     //
513     // Check to make sure we're acting on a real UART module.
514     //
515     am_hal_debug_assert_msg(ui32Module < AM_REG_UART_NUM_MODULES,
516                             "Trying to disable a UART module that doesn't exist");
517 
518     //
519     // Save all of the configuration register information for the selected
520     // UART.
521     //
522     am_hal_uart_pwrsave[ui32Module].ILPR = AM_REGn(UART, ui32Module, ILPR);
523     am_hal_uart_pwrsave[ui32Module].IBRD = AM_REGn(UART, ui32Module, IBRD);
524     am_hal_uart_pwrsave[ui32Module].FBRD = AM_REGn(UART, ui32Module, FBRD);
525     am_hal_uart_pwrsave[ui32Module].LCRH = AM_REGn(UART, ui32Module, LCRH);
526     am_hal_uart_pwrsave[ui32Module].CR = AM_REGn(UART, ui32Module, CR);
527     am_hal_uart_pwrsave[ui32Module].IFLS = AM_REGn(UART, ui32Module, IFLS);
528     am_hal_uart_pwrsave[ui32Module].IER = AM_REGn(UART, ui32Module, IER);
529 
530     //
531     // Save the clock setting and disable power to the selected UART.
532     // Save the current enable value.
533     //
534     am_hal_uart_pwrsave[ui32Module].UARTEN =
535         (AM_REG(CLKGEN, UARTEN) & AM_HAL_CLKGEN_UARTEN_UARTENn_M(ui32Module)) >>
536          AM_HAL_CLKGEN_UARTEN_UARTENn_S(ui32Module);
537 
538     //
539     // Disable the UART.
540     //
541     am_hal_clkgen_uarten_set(ui32Module, AM_HAL_CLKGEN_UARTEN_DIS);
542 
543     //
544     // Indicates we have a valid saved configuration.
545     //
546     am_hal_uart_pwrsave[ui32Module].bValid = 1;
547 
548     //
549     // Disable power to the selected UART.
550     //
551     am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_UART0 << ui32Module);
552 
553     return;
554 }
555 
556 //*****************************************************************************
557 //
558 //! @brief Enable the UART clock.
559 //!
560 //! This function enables the clock to the UART.
561 //!
562 //! @return None.
563 //
564 //*****************************************************************************
565 void
am_hal_uart_clock_enable(uint32_t ui32Module)566 am_hal_uart_clock_enable(uint32_t ui32Module)
567 {
568     //
569     // Set CLKGEN.UARTEN, clear the field then write the desired enable value
570     // Valid enable values are DIS, EN, REDUCE_FREQ, EN_POWER_SAV.
571     //
572     am_hal_clkgen_uarten_set(ui32Module, AM_HAL_CLKGEN_UARTEN_EN);
573 
574     //
575     // Enable the UART clock.
576     //
577     AM_REGn(UART, ui32Module, CR) |= AM_REG_UART_CR_CLKEN_M;
578 
579     //
580     // Select default UART clock source
581     //
582     AM_REGn(UART, ui32Module, CR) |= AM_REG_UART_CR_CLKSEL_24MHZ;
583 }
584 
585 //*****************************************************************************
586 //
587 //! @brief Disable the UART clock.
588 //!
589 //! This function disables the clock to the UART.
590 //!
591 //! @return None.
592 //
593 //*****************************************************************************
594 void
am_hal_uart_clock_disable(uint32_t ui32Module)595 am_hal_uart_clock_disable(uint32_t ui32Module)
596 {
597     //
598     // Disable the UART clock.
599     //
600     AM_REGn(UART, ui32Module, CR) &= ~AM_REG_UART_CR_CLKEN_M;
601 
602     //
603     // Disable the UART clock in the CLKGEN module.
604     //
605     am_hal_clkgen_uarten_set(ui32Module, AM_HAL_CLKGEN_UARTEN_DIS);
606 }
607 
608 //*****************************************************************************
609 //
610 //! @brief Set and enable the desired interrupt levels for the RX/TX fifo.
611 //!
612 //! @param ui32LvlCfg - Desired FIFO RX/TX levels.
613 //!
614 //! This function sets the desired interrupt levels for the RX/TX fifo and
615 //! enables the use of transmit and receive FIFO buffers.
616 //!
617 //! Valid values for ui32LvlCfg are:
618 //!
619 //!     AM_HAL_UART_TX_FIFO_1_8
620 //!     AM_HAL_UART_TX_FIFO_1_4
621 //!     AM_HAL_UART_TX_FIFO_1_2
622 //!     AM_HAL_UART_TX_FIFO_3_4
623 //!     AM_HAL_UART_TX_FIFO_7_8
624 //!
625 //!     AM_HAL_UART_RX_FIFO_1_8
626 //!     AM_HAL_UART_RX_FIFO_1_4
627 //!     AM_HAL_UART_RX_FIFO_1_2
628 //!     AM_HAL_UART_RX_FIFO_3_4
629 //!     AM_HAL_UART_RX_FIFO_7_8
630 //!
631 //! @return None.
632 //
633 //*****************************************************************************
634 void
am_hal_uart_fifo_config(uint32_t ui32Module,uint32_t ui32LvlCfg)635 am_hal_uart_fifo_config(uint32_t ui32Module, uint32_t ui32LvlCfg)
636 {
637     //
638     // Enable the use of FIFOs.
639     //
640     AM_REGn(UART, ui32Module, LCRH) |= AM_REG_UART_LCRH_FEN_M;
641 
642     //
643     // Write the FIFO level register.
644     //
645     AM_REGn(UART, ui32Module, IFLS) = ui32LvlCfg;
646 }
647 
648 //*****************************************************************************
649 //
650 //! @brief Return the UART Flags.
651 //!
652 //! This function reads and returns the UART flags.
653 //!
654 //! @return Returns the Flags.
655 //
656 //*****************************************************************************
657 uint32_t
am_hal_uart_flags_get(uint32_t ui32Module)658 am_hal_uart_flags_get(uint32_t ui32Module)
659 {
660     //
661     // Read and return the Flags.
662     //
663     return AM_REGn(UART, ui32Module, FR);
664 }
665 
666 //*****************************************************************************
667 //
668 //! @brief Outputs a single character using polling.
669 //!
670 //! @param cChar - Character to send.
671 //!
672 //! This function outputs a single character using polling.
673 //!
674 //! @return None.
675 //
676 //*****************************************************************************
677 void
am_hal_uart_char_transmit_polled(uint32_t ui32Module,char cChar)678 am_hal_uart_char_transmit_polled(uint32_t ui32Module, char cChar)
679 {
680     //
681     // Wait for space, i.e.  TX FIFO EMPTY
682     //
683     while (AM_BFRn(UART, ui32Module, FR, TXFF));
684 
685     //
686     // Write the char.
687     //
688     AM_REGn(UART, ui32Module, DR) = cChar;
689 }
690 
691 //*****************************************************************************
692 //
693 //! @brief Outputs a zero terminated string using polling.
694 //!
695 //! @param pcString - Pointer to character string to send.
696 //!
697 //! This function outputs a zero terminated string using polling.
698 //!
699 //! @return None.
700 //
701 //*****************************************************************************
702 void
am_hal_uart_string_transmit_polled(uint32_t ui32Module,char * pcString)703 am_hal_uart_string_transmit_polled(uint32_t ui32Module, char *pcString)
704 {
705     while (*pcString)
706     {
707         //
708         // Wait for space, i.e.  TX FIFO EMPTY.
709         //
710         while (AM_BFRn(UART, ui32Module, FR, TXFF));
711 
712         //
713         // Write the char.
714         //
715         AM_REGn(UART, ui32Module, DR) = *pcString++;
716     }
717 }
718 
719 //*****************************************************************************
720 //
721 //! @brief Receives a character using polling.
722 //!
723 //! @param pcChar - Pointer to character to store received char.
724 //!
725 //! This function receives a character using polling.
726 //!
727 //! @return None.
728 //
729 //*****************************************************************************
730 void
am_hal_uart_char_receive_polled(uint32_t ui32Module,char * pcChar)731 am_hal_uart_char_receive_polled(uint32_t ui32Module, char *pcChar)
732 {
733     //
734     // Wait for data, i.e. RX FIFO NOT EMPTY.
735     //
736     while (AM_BFRn(UART, ui32Module, FR, RXFE));
737 
738     //
739     // Save the char.
740     //
741     *pcChar = AM_REGn(UART, ui32Module, DR);
742 }
743 
744 //*****************************************************************************
745 //
746 //! @brief Receives one line using polling.
747 //!
748 //! @param ui32MaxChars - Maximum number of characters to receive.
749 //! @param pcChar - Pointer to character string to store received line.
750 //!
751 //! This function receives a line (delimited by '/n' or '/r') using polling.
752 //! Line buffer is 0 (NULL) terminated.
753 //!
754 //! @return None.
755 //
756 //*****************************************************************************
757 void
am_hal_uart_line_receive_polled(uint32_t ui32Module,uint32_t ui32MaxChars,char * pcChar)758 am_hal_uart_line_receive_polled(uint32_t ui32Module,
759                                 uint32_t ui32MaxChars,
760                                 char *pcChar)
761 {
762     char cRecChar;
763     uint32_t i;
764 
765     //
766     // Loop until we receive ui32MaxChars or receive a line ending.
767     //
768     for (i = 0; i < (ui32MaxChars - 1); i++)
769     {
770         //
771         // Get char.
772         //
773         am_hal_uart_char_receive_polled(ui32Module, &cRecChar);
774 
775         if ((cRecChar == '\n') || (cRecChar == '\r'))
776         {
777             //
778             // Zero terminate the buffer.
779             //
780             *pcChar = 0;
781 
782             return;
783         }
784 
785         *pcChar++ = cRecChar;
786     }
787 }
788 
789 //*****************************************************************************
790 //
791 //! @brief Initialize the buffered UART.
792 //!
793 //! @param pui8RxArray - Pointer to the RX buffer to fill.
794 //! @param ui32RxSize - size of RX buffer.
795 //! @param pui8TxArray - Pointer to the TX buffer to fill.
796 //! @param ui32TxSize - size of TX buffer.
797 //!
798 //! This function initializes the buffered UART.
799 //!
800 //! @return None.
801 //
802 //*****************************************************************************
803 void
am_hal_uart_init_buffered(uint32_t ui32Module,uint8_t * pui8RxArray,uint32_t ui32RxSize,uint8_t * pui8TxArray,uint32_t ui32TxSize)804 am_hal_uart_init_buffered(uint32_t ui32Module,
805                           uint8_t *pui8RxArray, uint32_t ui32RxSize,
806                           uint8_t *pui8TxArray, uint32_t ui32TxSize)
807 {
808     //
809     // Enable the UART RX timeout interrupt.
810     //
811     AM_REGn(UART, ui32Module, IER) |= (AM_REG_UART_IES_RTRIS_M |
812                                        AM_REG_UART_IES_TXRIS_M);
813 
814     //
815     // Initialize the ring buffers.
816     //
817     am_hal_queue_init(&g_psTxQueue[ui32Module], pui8TxArray, 1, ui32TxSize);
818     am_hal_queue_init(&g_psRxQueue[ui32Module], pui8RxArray, 1, ui32RxSize);
819 }
820 
821 //*****************************************************************************
822 //
823 //! @brief Get the status of the buffered UART.
824 //!
825 //! @param pui32RxSize - Pointer to variable to return the Rx ring data size.
826 //! @param pui32TxSize - Pointer to variable to return the Tx ring data size.
827 //!
828 //! This function gets the status of the buffered UART.
829 //!
830 //! @return None.
831 //
832 //*****************************************************************************
833 void
am_hal_uart_get_status_buffered(uint32_t ui32Module,uint32_t * pui32RxSize,uint32_t * pui32TxSize)834 am_hal_uart_get_status_buffered(uint32_t ui32Module,
835                                 uint32_t *pui32RxSize,
836                                 uint32_t *pui32TxSize)
837 {
838     //
839     // Return the current size of ring buffers.
840     //
841     if ( pui32RxSize )
842     {
843         *pui32RxSize = am_hal_queue_data_left(&g_psRxQueue[ui32Module]);
844     }
845 
846     if ( pui32TxSize )
847     {
848         *pui32TxSize = am_hal_queue_data_left(&g_psTxQueue[ui32Module]);
849     }
850 }
851 
852 
853 //*****************************************************************************
854 //
855 //! @brief Services the buffered UART.
856 //!
857 //! @param ui32Status is the contents of the UART interrupt status register.
858 //!
859 //! This function is responsible for servicing the buffered UART. Designed to
860 //! be called from the UART interrupt handler.
861 //!
862 //! @return None
863 //
864 //*****************************************************************************
865 void
am_hal_uart_service_buffered(uint32_t ui32Module,uint32_t ui32Status)866 am_hal_uart_service_buffered(uint32_t ui32Module, uint32_t ui32Status)
867 {
868     uint8_t ui8Character = '\x00';
869     uint32_t ui32FifoEntry = 0;
870 
871     //
872     // Check to see if we have filled the Rx FIFO past the configured limit, or
873     // if we have an 'old' character or two sitting in the FIFO.
874     //
875     if (ui32Status & (AM_REG_UART_IES_RXRIS_M | AM_REG_UART_IES_RTRIS_M))
876     {
877         //
878         // While there's stuff in the RX fifo....
879         //
880         while (!AM_BFRn(UART, ui32Module, FR, RXFE))
881         {
882             //
883             // Read each character out one by one, and add it to the ring
884             // buffer. This will start losing bytes if the fifo ever overflows.
885             //
886             ui32FifoEntry = AM_REGn(UART, ui32Module , DR);
887 
888             //
889             // As long as no error bits were set, we should push this byte to
890             // the FIFO.
891             //
892             if ( (ui32FifoEntry & 0xF00) == 0 )
893             {
894                 ui8Character = ui32FifoEntry & 0xFF;
895                 am_hal_queue_item_add(&g_psRxQueue[ui32Module], &ui8Character, 1);
896             }
897         }
898     }
899 
900     //
901     // Check to see if our TX buffer has been recently emptied. If so, we
902     // should refill it from the TX ring buffer.
903     //
904     if (ui32Status & AM_REG_UART_IES_TXRIS_M)
905     {
906         //
907         // Keep refilling until the fifo is full, or the ring buffer is empty,
908         // whichever happens first.
909         //
910         while (am_hal_queue_data_left(&g_psTxQueue[ui32Module]) &&
911                !AM_BFRn(UART, ui32Module, FR, TXFF))
912         {
913             am_hal_queue_item_get(&g_psTxQueue[ui32Module], &ui8Character, 1);
914             AM_REGn(UART, ui32Module , DR) = ui8Character;
915         }
916     }
917 }
918 
919 //*****************************************************************************
920 //
921 //! @brief Services the buffered UART.
922 //!
923 //! @param ui32Status is the contents of the UART interrupt status register.
924 //!
925 //! This function is responsible for servicing the buffered UART. Designed to
926 //! be called from the UART interrupt handler.
927 //!
928 //! This function behaves exactly like am_hal_uart_service_buffered() \e except
929 //! it does not completely empty the RX FIFO on every interrupt event. Instead,
930 //! it will leave at least one byte behind until it receives a UART RX TIMEOUT
931 //! interrupt. If you use this service routine, you can treat the RX TIMEOUT
932 //! interrupt as a UART IDLE interrupt. Every time the UART RX line goes IDLE
933 //! for 32 consecutive bit-times you WILL receive a UART RX TIMEOUT interrupt.
934 //! This behavior is not guaranteed for am_hal_uart_service_buffered().
935 //!
936 //! @return None
937 //
938 //*****************************************************************************
939 void
am_hal_uart_service_buffered_timeout_save(uint32_t ui32Module,uint32_t ui32Status)940 am_hal_uart_service_buffered_timeout_save(uint32_t ui32Module, uint32_t ui32Status)
941 {
942     uint8_t ui8Character = '\x00';
943     uint32_t ui32Count = 0;
944     uint32_t ui32FifoEntry = 0;
945 
946     //
947     // Check to see if we have filled the Rx FIFO past the configured limit, or
948     // if we have an 'old' character or two sitting in the FIFO.
949     //
950     if (ui32Status & (AM_REG_UART_IES_RXRIS_M | AM_REG_UART_IES_RTRIS_M))
951     {
952         //
953         // Check to see what our FIFO configuration setting is.
954         //
955         uint32_t ui32FifoThreshold;
956         uint32_t ui32FifoCfg = AM_BFMn(UART, ui32Module, IFLS, RXIFLSEL);
957 
958         //
959         // Compute the number of bytes for receive interrupt from the FIFO level
960         // register.
961         //
962         switch(ui32FifoCfg)
963         {
964             case AM_HAL_UART_RX_FIFO_1_8: ui32FifoThreshold = 4; break;
965             case AM_HAL_UART_RX_FIFO_1_4: ui32FifoThreshold = 8; break;
966             case AM_HAL_UART_RX_FIFO_1_2: ui32FifoThreshold = 16; break;
967             case AM_HAL_UART_RX_FIFO_3_4: ui32FifoThreshold = 24; break;
968             case AM_HAL_UART_RX_FIFO_7_8: ui32FifoThreshold = 28; break;
969             default:
970                 ui32FifoThreshold = 32;
971         }
972 
973         //
974         // While there's stuff in the RX fifo....
975         //
976         while (!AM_BFRn(UART, ui32Module, FR, RXFE))
977         {
978             //
979             // Read each character out one by one, and add it to the ring
980             // buffer. This will start losing bytes if the fifo ever overflows.
981             //
982             ui32FifoEntry = AM_REGn(UART, ui32Module, DR);
983 
984             //
985             // As long as no error bits were set, we should push this byte to
986             // the FIFO.
987             //
988             if ( (ui32FifoEntry & 0xF00) == 0)
989             {
990                 ui8Character = ui32FifoEntry & 0xFF;
991                 am_hal_queue_item_add(&g_psRxQueue[ui32Module], &ui8Character, 1);
992             }
993 
994             //
995             // Leave one byte to trigger the RX timeout interrupt.
996             //
997             if ( ++ui32Count >= (ui32FifoThreshold - 1) )
998             {
999                 break;
1000             }
1001         }
1002     }
1003 
1004     //
1005     // Check to see if our TX buffer has been recently emptied. If so, we
1006     // should refill it from the TX ring buffer.
1007     //
1008     if (ui32Status & AM_REG_UART_IES_TXRIS_M)
1009     {
1010         //
1011         // Keep refilling until the fifo is full, or the ring buffer is empty,
1012         // whichever happens first.
1013         //
1014         while (am_hal_queue_data_left(&g_psTxQueue[ui32Module]) &&
1015                !AM_BFRn(UART, ui32Module, FR, TXFF))
1016         {
1017             am_hal_queue_item_get(&g_psTxQueue[ui32Module], &ui8Character, 1);
1018             AM_REGn(UART, ui32Module , DR) = ui8Character;
1019         }
1020     }
1021 }
1022 
1023 //*****************************************************************************
1024 //
1025 //! @brief Puts a char in the buffer or directly to the fifo if available.
1026 //!
1027 //! @param cChar - Character to send.
1028 //!
1029 //! This function puts a character in the buffer or directly to the fifo.
1030 //!
1031 //! @return None.
1032 //
1033 //*****************************************************************************
1034 void
am_hal_uart_char_transmit_buffered(uint32_t ui32Module,char cChar)1035 am_hal_uart_char_transmit_buffered(uint32_t ui32Module, char cChar)
1036 {
1037     //
1038     // Check the status of the Tx fifo and the Tx ring buffer.
1039     //
1040     if (am_hal_queue_empty(&g_psTxQueue[ui32Module]) &&
1041         !AM_BFRn(UART, ui32Module, FR, TXFF))
1042     {
1043         //
1044         // If the fifo isn't full yet, and the ring buffer isn't being used,
1045         // just write the new character directly to the fifo.
1046         //
1047         AM_REGn(UART, ui32Module, DR) = cChar;
1048     }
1049     else
1050     {
1051         //
1052         // If we get here, either the fifo is full, or the ring buffer is
1053         // already in use. In either case, we need to use the ring buffer
1054         // to make sure that the transmitted data gets sent in the right
1055         // order. If the buffer is already full, we will simply lose this
1056         // byte.
1057         //
1058         am_hal_queue_item_add(&g_psTxQueue[ui32Module], &cChar, 1);
1059     }
1060 }
1061 
1062 //*****************************************************************************
1063 //
1064 //! @brief Puts a null terminaled string in the buffer or directly to the fifo.
1065 //!
1066 //! @param pcString - Pointer to buffer used for sending.
1067 //!
1068 //! This function puts a string in the buffer or directly to the fifo if there
1069 //! is space available.
1070 //!
1071 //! @return None.
1072 //
1073 //*****************************************************************************
1074 void
am_hal_uart_string_transmit_buffered(uint32_t ui32Module,char * pcString)1075 am_hal_uart_string_transmit_buffered(uint32_t ui32Module, char *pcString)
1076 {
1077     //
1078     // Check the status of the Tx fifo and the Tx ring buffer.
1079     //
1080     while (*pcString)
1081     {
1082         if (am_hal_queue_empty(&g_psTxQueue[ui32Module]) &&
1083             !AM_BFRn(UART, ui32Module, FR, TXFF))
1084         {
1085             //
1086             // If the fifo isn't full yet, and the ring buffer isn't being used,
1087             // just write the new character directly to the fifo.
1088             //
1089             AM_REGn(UART, ui32Module, DR) = *pcString;
1090         }
1091         else
1092         {
1093             //
1094             // If we get here, either the fifo is full, or the ring buffer is
1095             // already in use. In either case, we need to use the ring buffer
1096             // to make sure that the transmitted data gets sent in the right
1097             // order. If the buffer is already full, we will simply lose this
1098             // byte.
1099             //
1100             am_hal_queue_item_add(&g_psTxQueue[ui32Module], pcString, 1);
1101         }
1102 
1103         //
1104         // Move the pointer to the next character.
1105         //
1106         pcString++;
1107     }
1108 }
1109 
1110 //*****************************************************************************
1111 //
1112 //! @brief Returns n number of characters from the ring buffer or until empty.
1113 //!
1114 //! @param pcString - Pointer to buffer for putting received characters.
1115 //! @param ui32MaxChars - Maximum number of characters to receive.
1116 //!
1117 //! This function puts a char string in the buffer.
1118 //!
1119 //! @return Returns the number of chars received.
1120 //
1121 //*****************************************************************************
1122 uint32_t
am_hal_uart_char_receive_buffered(uint32_t ui32Module,char * pcString,uint32_t ui32MaxChars)1123 am_hal_uart_char_receive_buffered(uint32_t ui32Module,
1124                                   char *pcString,
1125                                   uint32_t ui32MaxChars)
1126 {
1127     uint32_t ui32NumChars = 0;
1128 
1129     //
1130     // Loop until ui32MaxChars or until empty.
1131     //
1132     while (am_hal_queue_data_left(&g_psRxQueue[ui32Module]) && ui32MaxChars)
1133     {
1134         //
1135         // Pull a char out of the ring buffer.
1136         //
1137         am_hal_queue_item_get(&g_psRxQueue[ui32Module], pcString, 1);
1138 
1139         //
1140         // Subtract from ui32MaxChars.
1141         // Add to ui32NumChars.
1142         // Move pointer in buffer.
1143         //
1144         ui32MaxChars--;
1145         ui32NumChars++;
1146         pcString++;
1147     }
1148 
1149     //
1150     // return the number of chars received.
1151     //
1152     return ui32NumChars;
1153 }
1154 
1155 //*****************************************************************************
1156 //
1157 // End Doxygen group.
1158 //! @}
1159 //
1160 //*****************************************************************************
1161