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