diff options
Diffstat (limited to 'libopencm3/lib/lpc43xx/uart.c')
-rw-r--r-- | libopencm3/lib/lpc43xx/uart.c | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/libopencm3/lib/lpc43xx/uart.c b/libopencm3/lib/lpc43xx/uart.c new file mode 100644 index 0000000..3168ce2 --- /dev/null +++ b/libopencm3/lib/lpc43xx/uart.c @@ -0,0 +1,243 @@ +/* +* This file is part of the libopencm3 project. +* +* Copyright (C) 2012 Benjamin Vernoux <titanmkd@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/>. +*/ + +#include <libopencm3/lpc43xx/uart.h> +#include <libopencm3/lpc43xx/cgu.h> + +#define UART_SRC_32K 0x00 +#define UART_SRC_IRC 0x01 +#define UART_SRC_ENET_RX 0x02 +#define UART_SRC_ENET_TX 0x03 +#define UART_SRC_GP_CLKIN 0x04 +#define UART_SRC_XTAL 0x06 +#define UART_SRC_PLL0USB 0x07 +#define UART_SRC_PLL0AUDIO 0x08 +#define UART_SRC_PLL1 0x09 +#define UART_SRC_IDIVA 0x0C +#define UART_SRC_IDIVB 0x0D +#define UART_SRC_IDIVC 0x0E +#define UART_SRC_IDIVD 0x0F +#define UART_SRC_IDIVE 0x10 + +#define UART_CGU_AUTOBLOCK_CLOCK_BIT 11 +/* clock source selection (5 bits) */ +#define UART_CGU_BASE_CLK_SEL_SHIFT 24 + +uint32_t dummy_read; + +/* +* UART Init function +*/ +void uart_init(uart_num_t uart_num, uart_databit_t data_nb_bits, + uart_stopbit_t data_nb_stop, uart_parity_t data_parity, + uint16_t uart_divisor, uint8_t uart_divaddval, uint8_t uart_mulval) +{ + uint32_t lcr_config; + uint32_t uart_port; + + uart_port = uart_num; + + switch (uart_num) { + case UART0_NUM: + /* use PLL1 as clock source for UART0 */ + CGU_BASE_UART0_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) | + (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT); + break; + + case UART1_NUM: + /* use PLL1 as clock source for UART1 */ + CGU_BASE_UART1_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) | + (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT); + break; + + case UART2_NUM: + /* use PLL1 as clock source for UART2 */ + CGU_BASE_UART2_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) | + (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT); + break; + + case UART3_NUM: + /* use PLL1 as clock source for UART3 */ + CGU_BASE_UART3_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) | + (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT); + break; + + default: + return; /* error */ + } + + /* FIFOs RX/TX Enabled and Reset RX/TX FIFO (DMA Mode is also cleared)*/ + UART_FCR(uart_port) = (UART_FCR_FIFO_EN | UART_FCR_RX_RS | + UART_FCR_TX_RS); + /* Disable FIFO */ + UART_FCR(uart_port) = 0; + + /* Dummy read (to clear existing data) */ + while (UART_LSR(uart_port) & UART_LSR_RDR) { + dummy_read = UART_RBR(uart_port); + } + + /* Wait end of TX & disable TX */ + UART_TER(uart_port) = UART_TER_TXEN; + + /* Wait for current transmit complete */ + while (!(UART_LSR(uart_port) & UART_LSR_THRE)); + + /* Disable Tx */ + UART_TER(uart_port) = 0; + + /* Disable interrupt */ + UART_IER(uart_port) = 0; + + /* Set LCR to default state */ + UART_LCR(uart_port) = 0; + + /* Set ACR to default state */ + UART_ACR(uart_port) = 0; + + /* Dummy Read to Clear Status */ + dummy_read = UART_LSR(uart_port); + + /* + Table 835. USART Fractional Divider Register: + UARTbaudrate = PCLK / ( 16* (((256*DLM)+ DLL)*(1+(DivAddVal/MulVal))) ) + The value of MULVAL and DIVADDVAL should comply to the following + conditions: + 1. 1 <= MULVAL <= 15 + 2. 0 <= DIVADDVAL <= 14 + 3. DIVADDVAL < MULVAL + */ + + /* Set DLAB Bit */ + UART_LCR(uart_port) |= UART_LCR_DLAB_EN; + UART_DLM(uart_port) = UART_LOAD_DLM(uart_divisor); + UART_DLL(uart_port) = UART_LOAD_DLL(uart_divisor); + /* Clear DLAB Bit */ + UART_LCR(uart_port) &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK; + UART_FDR(uart_port) = UART_FDR_BITMASK & + (UART_FDR_MULVAL(uart_mulval) | UART_FDR_DIVADDVAL(uart_divaddval)); + + /* Read LCR config & Force Enable of Divisor Latches Access */ + lcr_config = (UART_LCR(uart_port) & UART_LCR_DLAB_EN) & + UART_LCR_BITMASK; + lcr_config |= data_nb_bits; /* Set Nb Data Bits */ + lcr_config |= data_nb_stop; /* Set Nb Stop Bits */ + lcr_config |= data_parity; /* Set Data Parity */ + + /* Write LCR (only 8bits) */ + UART_LCR(uart_port) = (lcr_config & UART_LCR_BITMASK); + + /* Enable TX */ + UART_TER(uart_port) = UART_TER_TXEN; +} + +/* +* This Function return if data are received or not received. +*/ +uart_rx_data_ready_t uart_rx_data_ready(uart_num_t uart_num) +{ + uint32_t uart_port; + uint8_t uart_status; + uart_rx_data_ready_t data_ready; + + uart_port = uart_num; + + uart_status = UART_LSR(uart_port) & 0xFF; + + /* Check Error */ + if ((uart_status & UART_LSR_ERROR_MASK) == 0) { + /* No errors check if data is ready */ + if ((uart_status & UART_LSR_RDR) == 0) { + data_ready = UART_RX_NO_DATA; + } else { + data_ready = UART_RX_DATA_READY; + } + } else { + /* UART Error */ + data_ready = UART_RX_DATA_ERROR; + } + + return data_ready; +} + +/* +* This Function Wait until Data RX Ready, and return Data Read from UART. +*/ +uint8_t uart_read(uart_num_t uart_num) +{ + uint32_t uart_port; + uint8_t uart_val; + + uart_port = uart_num; + + /* Wait Until Data Received (Rx Data Not Ready) */ + while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0); + + uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT); + + return uart_val; +} + +/* +* This Function Wait until Data RX Ready, and return Data Read from UART. +*/ +uint8_t uart_read_timeout(uart_num_t uart_num, uint32_t rx_timeout_nb_cycles, + uart_error_t *error) +{ + uint32_t uart_port; + uint8_t uart_val; + uint32_t counter; + + uart_port = uart_num; + + /* Wait Until Data Received (Rx Data Not Ready) */ + counter = 0; + while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0) { + if (rx_timeout_nb_cycles > 0) { + counter++; + if (counter >= rx_timeout_nb_cycles) { + *error = UART_TIMEOUT_ERROR; + return 0; + } + } + } + + uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT); + + /* Clear error */ + *error = UART_NO_ERROR; + + return uart_val; +} + +/* This Function Wait Data TX Ready, and Write Data to UART + if rx_timeout_nb_cycles = 0 Infinite wait +*/ +void uart_write(uart_num_t uart_num, uint8_t data) +{ + uint32_t uart_port; + + uart_port = uart_num; + + /* Wait Until FIFO not full */ + while ((UART_LSR(uart_port) & UART_LSR_THRE) == 0); + + UART_THR(uart_port) = data; +} + |