1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
|
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @defgroup uart_file UART
*
* @ingroup LM4Fxx
*
* @author @htmlonly © @endhtmlonly 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* \brief <b>libopencm3 LM4F Universal Asynchronous Receiver Transmitter</b>
*
* The LM4F UART API provides functionality for accessing the UART hardware of
* the LM4F.
*
* Please see the individual UART modules for more details. To use the UART, the
* uart.h header needs to be included:
* @code{.c}
* #include <libopencm3/lm4f/uart.h>
* @endcode
*
* @{
*/
#include <libopencm3/lm4f/uart.h>
#include <libopencm3/lm4f/systemcontrol.h>
#include <libopencm3/lm4f/rcc.h>
/** @defgroup uart_config UART configuration
* @ingroup uart_file
*
* \brief <b>Enabling and configuring the UART</b>
*
* Enabling the UART is a two step process. The GPIO on which the UART resides
* must be enabled, and the UART pins must be configured as alternate function,
* digital pins. Pins must also be muxed to the appropriate alternate function.
* This is done with the GPIO API.
*
* The second step involves enabling and the UART itself. The UART should be
* disabled while it is being configured.
* -# The UART clock must be enabled with @ref periph_clock_enable().
* -# The UART must be disabled with @ref uart_disable().
* -# The UART clock source should be chosen before setting the baudrate.
* -# Baudrate, data bits, stop bit length, and parity can be configured.
* -# If needed, enable CTS or RTS lines via the @ref uart_set_flow_control().
* -# The UART can now be enabled with @ref uart_enable().
*
* For example, to enable UART1 at 115200 8n1 with hardware flow control:
* @code{.c}
* // Enable the UART clock
* periph_clock_enable(RCC_UART1);
* // We need a brief delay before we can access UART config registers
* __asm__("nop"); __asm__("nop"); __asm__("nop");
* // Disable the UART while we mess with its settings
* uart_disable(UART1);
* // Configure the UART clock source as precision internal oscillator
* uart_clock_from_piosc();
* // Set communication parameters
* uart_set_baudrate(UART1, 115200);
* uart_set_databits(UART1, 8);
* uart_set_parity(UART1, UART_PARITY_NONE);
* uart_set_stopbits(UART1, 1);
* // Enable RTC and CTS lines
* uart_set_flow_control(UART1, UART_FLOWCTL_HARD_RTS_CTS);
* // Now that we're done messing with the settings, enable the UART
* uart_enable(UART1);
* @endcode
*/
/**@{*/
/**
* \brief Enable the UART
*
* Enable the UART. The Rx and Tx lines are also enabled.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable(uint32_t uart)
{
UART_CTL(uart) |= (UART_CTL_UARTEN | UART_CTL_RXE | UART_CTL_TXE);
}
/**
* \brief Disable the UART
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable(uint32_t uart)
{
UART_CTL(uart) &= ~UART_CTL_UARTEN;
}
/**
* \brief Set UART baudrate
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] baud Baud rate in bits per second (bps).*
*/
void uart_set_baudrate(uint32_t uart, uint32_t baud)
{
uint32_t clock;
/* Are we running off the internal clock or system clock? */
if (UART_CC(uart) == UART_CC_CS_PIOSC) {
clock = 16000000;
} else {
clock = rcc_get_system_clock_frequency();
}
/* Find the baudrate divisor */
uint32_t div = (((clock * 8) / baud) + 1) / 2;
/* Set the baudrate divisors */
UART_IBRD(uart) = div / 64;
UART_FBRD(uart) = div % 64;
}
/**
* \brief Set UART databits
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] databits number of data bits per transmission.
*/
void uart_set_databits(uint32_t uart, uint8_t databits)
{
uint32_t reg32, bitint32_t;
/* This has the same effect as using UART_LCRH_WLEN_5/6/7/8 directly */
bitint32_t = (databits - 5) << 5;
/* TODO: What about 9 data bits? */
reg32 = UART_LCRH(uart);
reg32 &= ~UART_LCRH_WLEN_MASK;
reg32 |= bitint32_t;
UART_LCRH(uart) = reg32;
}
/**
* \brief Set UART stopbits
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] bits the requested number of stopbits, either 1 or 2.
*/
void uart_set_stopbits(uint32_t uart, uint8_t stopbits)
{
if (stopbits == 2) {
UART_LCRH(uart) |= UART_LCRH_STP2;
} else {
UART_LCRH(uart) &= ~UART_LCRH_STP2;
}
}
/**
* \brief Set UART parity
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] bits the requested parity scheme.
*/
void uart_set_parity(uint32_t uart, enum uart_parity parity)
{
uint32_t reg32;
reg32 = UART_LCRH(uart);
reg32 |= UART_LCRH_PEN;
reg32 &= ~(UART_LCRH_SPS | UART_LCRH_EPS);
switch (parity) {
case UART_PARITY_NONE:
/* Once we disable parity the other bits are meaningless */
UART_LCRH(uart) &= ~UART_LCRH_PEN;
return;
case UART_PARITY_ODD:
break;
case UART_PARITY_EVEN:
reg32 |= UART_LCRH_EPS;
break;
case UART_PARITY_STICK_0:
reg32 |= (UART_LCRH_SPS | UART_LCRH_EPS);
break;
case UART_PARITY_STICK_1:
reg32 |= UART_LCRH_SPS;
break;
}
UART_LCRH(uart) = reg32;
}
/**
* \brief Set the flow control scheme
*
* Set the flow control scheme by enabling or disabling RTS and CTS lines. This
* will only have effect if the given UART supports the RTS and CTS lines.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] flow The flow control scheme to use (none, RTS, CTS or both) \n
* UART_FLOWCTL_RTS -- enable the RTS line \n
* UART_FLOWCTL_CTS -- enable the CTS line \n
* UART_FLOWCTL_RTS_CTS -- enable both RTS and CTS lines
*/
void uart_set_flow_control(uint32_t uart, enum uart_flowctl flow)
{
uint32_t reg32 = UART_CTL(uart);
reg32 &= ~(UART_CTL_RTSEN | UART_CTL_CTSEN);
if (flow == UART_FLOWCTL_RTS) {
reg32 |= UART_CTL_RTSEN;
} else if (flow == UART_FLOWCTL_CTS) {
reg32 |= UART_CTL_CTSEN;
} else if (flow == UART_FLOWCTL_RTS_CTS) {
reg32 |= (UART_CTL_RTSEN | UART_CTL_CTSEN);
}
UART_CTL(uart) = reg32;
}
/**
* \brief Clock the UART module from the internal oscillator
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_clock_from_piosc(uint32_t uart)
{
UART_CC(uart) = UART_CC_CS_PIOSC;
}
/**
* \brief Clock the UART module from the system clock
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_clock_from_sysclk(uint32_t uart)
{
UART_CC(uart) = UART_CC_CS_SYSCLK;
}
/**@}*/
/** @defgroup uart_send_recv UART transmission and reception
* @ingroup uart_file
*
* \brief <b>Sending and receiving data through the UART</b>
*
* Primitives for sending and recieving data are provided, @ref uart_send() and
* @ref uart_recv(). These primitives do not check if data can be transmitted
* or wait for data. If waiting until data is available or can be transmitted is
* desired, blocking primitives are also available, @ref uart_send_blocking()
* and @ref uart_recv_blocking().
*
* These primitives only handle one byte at at time, and thus may be unsuited
* for some applications. You may also consider using @ref uart_dma.
*/
/**@{*/
/**
* \brief UART Send a Data Word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] data data to send.
*/
void uart_send(uint32_t uart, uint16_t data)
{
data &= 0xFF;
UART_DR(uart) = data;
}
/**
* \brief UART Read a Received Data Word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @return data from the Rx FIFO.
*/
uint16_t uart_recv(uint32_t uart)
{
return UART_DR(uart) & UART_DR_DATA_MASK;
}
/**
* \brief UART Wait for Transmit Data Buffer Not Full
*
* Blocks until the transmit data FIFO is not empty and can accept the next data
* word.
* \n
* Even if the FIFO is not empty, this function will return as long as there is
* room for at least one more word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_wait_send_ready(uint32_t uart)
{
/* Wait until the Tx FIFO is no longer full */
while (UART_FR(uart) & UART_FR_TXFF);
}
/**
* \brief UART Wait for Received Data Available
*
* Blocks until the receive data FIFO holds a at least valid received data word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_wait_recv_ready(uint32_t uart)
{
/* Wait until the Tx FIFO is no longer empty */
while (UART_FR(uart) & UART_FR_RXFE);
}
/**
* \brief UART Send Data Word with Blocking
*
* Blocks until the transmit data FIFO can accept the next data word for
* transmission.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_send_blocking(uint32_t uart, uint16_t data)
{
uart_wait_send_ready(uart);
uart_send(uart, data);
}
/**
* \brief UART Read a Received Data Word with Blocking.
*
* Wait until a data word has been received then return the word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @return data from the Rx FIFO.
*/
uint16_t uart_recv_blocking(uint32_t uart)
{
uart_wait_recv_ready(uart);
return uart_recv(uart);
}
/**@}*/
/** @defgroup uart_irq UART Interrupt control
* @ingroup uart_file
*
* \brief <b>Configuring interrupts from the UART</b>
*
* To have an event generate an interrupt, its interrupt source must be
* unmasked. This can be achieved with @ref uart_enable_interrupts(). Interrupts
* which are no longer needed can be disabled through
* @ref uart_disable_interrupts().
*
* In order for the interrupt to generate an IRQ and a call to the interrupt
* service routine, the interrupt for the target UART must be routed through the
* NVIC with @ref nvic_enable_irq(). For this last step, the nvic.h header is
* needed:
* @code{.c}
* #include <libopencm3/lm4f/nvic.h>
* @endcode
*
* Enabling an interrupt is as simple as unmasking the desired interrupt, and
* routing the desired UART's interrupt through the NVIC.
* @code{.c}
* // Unmask receive interrupt
* uart_enable_rx_interrupt(UART0);
* // Make sure the interrupt is routed through the NVIC
* nvic_enable_irq(NVIC_UART0_IRQ);
* @endcode
*
* If a more than one interrupt is to be enabled at one time, the interrupts
* can be enabled by a single call to @ref uart_enable_interrupts().
* For example:
* @code{.c}
* // Unmask receive, CTS, and RI, interrupts
* uart_enable_interrupts(UART0, UART_INT_RX | UART_INT_RI | UART_INT_CTS);
* @endcode
*
* After interrupts are properly enabled and routed through the NVIC, when an
* event occurs, the appropriate IRQ flag is set by hardware, and execution
* jumps to the UART ISR. The ISR should query the IRQ flags to determine which
* event caused the interrupt. For this, use @ref uart_is_interrupt_source(),
* with the desired UART_INT flag. After one or more interrupt sources are
* serviced, the IRQ flags must be cleared by the ISR. This can be done with
* @ref uart_clear_interrupt_flag().
*
* A typical UART ISR may look like the following:
* @code{.c}
* void uart0_isr(void)
* {
* uint32_t serviced_irqs = 0;
*
* // Process individual IRQs
* if (uart_is_interrupt_source(UART0, UART_INT_RX)) {
* process_rx_event();
* serviced_irq |= UART_INT_RX;
* }
* if (uart_is_interrupt_source(UART0, UART_INT_CTS)) {
* process_cts_event();
* serviced_irq |= UART_INT_CTS;
* }
*
* // Clear the interupt flag for the processed IRQs
* uart_clear_interrupt_flag(UART0, serviced_irqs);
* }
* @endcode
*/
/**@{*/
/**
* \brief Enable Specific UART Interrupts
*
* Enable any combination of interrupts. Interrupts may be OR'ed together to
* enable them with one call. For example, to enable both the RX and CTS
* interrupts, pass (UART_INT_RX | UART_INT_CTS)
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to enable. Any combination of interrupts may
* be specified by OR'ing then together
*/
void uart_enable_interrupts(uint32_t uart, enum uart_interrupt_flag ints)
{
UART_IM(uart) |= ints;
}
/**
* \brief Enable Specific UART Interrupts
*
* Disabe any combination of interrupts. Interrupts may be OR'ed together to
* disable them with one call. For example, to disable both the RX and CTS
* interrupts, pass (UART_INT_RX | UART_INT_CTS)
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to disable. Any combination of interrupts
* may be specified by OR'ing then together
*/
void uart_disable_interrupts(uint32_t uart, enum uart_interrupt_flag ints)
{
UART_IM(uart) &= ~ints;
}
/**
* \brief Enable the UART Receive Interrupt.
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_rx_interrupt(uint32_t uart)
{
uart_enable_interrupts(uart, UART_INT_RX);
}
/**
* \brief Disable the UART Receive Interrupt.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_rx_interrupt(uint32_t uart)
{
uart_disable_interrupts(uart, UART_INT_RX);
}
/**
* \brief Enable the UART Transmit Interrupt.
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_tx_interrupt(uint32_t uart)
{
uart_enable_interrupts(uart, UART_INT_TX);
}
/**
* \brief Disable the UART Transmit Interrupt.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_tx_interrupt(uint32_t uart)
{
uart_disable_interrupts(uart, UART_INT_TX);
}
/**
* \brief Mark interrupt as serviced
*
* After an interrupt is services, its flag must be cleared. If the flag is not
* cleared, then execution will jump back to the start of the ISR after the ISR
* returns.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to clear. Any combination of interrupts may
* be specified by OR'ing then together
*/
void uart_clear_interrupt_flag(uint32_t uart, enum uart_interrupt_flag ints)
{
UART_ICR(uart) |= ints;
}
/**@}*/
/** @defgroup uart_dma UART DMA control
* @ingroup uart_file
*
* \brief <b>Enabling Direct Memory Access transfers for the UART</b>
*
*/
/**@{*/
/**
* \brief Enable the UART Receive DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_rx_dma(uint32_t uart)
{
UART_DMACTL(uart) |= UART_DMACTL_RXDMAE;
}
/**
* \brief Disable the UART Receive DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_rx_dma(uint32_t uart)
{
UART_DMACTL(uart) &= ~UART_DMACTL_RXDMAE;
}
/**
* \brief Enable the UART Transmit DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_tx_dma(uint32_t uart)
{
UART_DMACTL(uart) |= UART_DMACTL_TXDMAE;
}
/**
* \brief Disable the UART Transmit DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_tx_dma(uint32_t uart)
{
UART_DMACTL(uart) &= ~UART_DMACTL_TXDMAE;
}
/**@}*/
/** @defgroup uart_fifo UART FIFO control
* @ingroup uart_file
*
* \brief <b>Enabling and controlling UART FIFO</b>
*
* The UART on the LM4F can either be used with a single character TX and RX
* buffer, or with a 8 character TX and RX FIFO. In order to use the FIFO it
* must be enabled, this is done with uart_enable_fifo() and can be disabled
* again with uart_disable_fifo(). On reset the FIFO is disabled, and it must
* be explicitly be enabled.
*
* When enabling the UART FIFOs, RX and TX interrupts are triggered according
* to the amount of data in the FIFOs. For the RX FIFO the trigger level is
* defined by how full the FIFO is. The TX FIFO trigger level is defined by
* how empty the FIFO is instead.
*
* For example, to enable the FIFOs and trigger interrupts for a single
* received and single transmitted character:
* @code{.c}
* uart_enable_fifo(UART0);
* uart_set_fifo_trigger_levels(UART0, UART_FIFO_RX_TRIG_1_8,
* UART_FIFO_TX_TRIG_7_8);
* @endcode
*/
/**@{*/
/**
* \brief Enable FIFO for the UART.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_fifo(uint32_t uart)
{
UART_LCRH(uart) |= UART_LCRH_FEN;
}
/**
* \brief Disable FIFO for the UART.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_fifo(uint32_t uart)
{
UART_LCRH(uart) &= ~UART_LCRH_FEN;
}
/**
* \brief Set the FIFO trigger levels.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] rx_level Trigger level for RX FIFO
* @param[in] tx_level Trigger level for TX FIFO
*/
void uart_set_fifo_trigger_levels(uint32_t uart,
enum uart_fifo_rx_trigger_level rx_level,
enum uart_fifo_tx_trigger_level tx_level)
{
UART_IFLS(uart) = rx_level | tx_level;
}
/**@}*/
/**
* @}
*/
|