220 lines
7.8 KiB
C
220 lines
7.8 KiB
C
/*
|
|
* Copyright (c) 2011-2012, Freescale Semiconductor, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* o Redistributions of source code must retain the above copyright notice, this list
|
|
* of conditions and the following disclaimer.
|
|
*
|
|
* o Redistributions in binary form must reproduce the above copyright notice, this
|
|
* list of conditions and the following disclaimer in the documentation and/or
|
|
* other materials provided with the distribution.
|
|
*
|
|
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*!
|
|
* @file imx_uart.c
|
|
* @brief UART driver.
|
|
|
|
* @ingroup diag_uart
|
|
*/
|
|
|
|
#include "sdk.h"
|
|
#include "registers/regsuart.h"
|
|
#include "imx_uart.h"
|
|
#include "ccm_pll.h"
|
|
#include "interrupt.h"
|
|
|
|
#define UART_UFCR_RFDIV BF_UART_UFCR_RFDIV(4)
|
|
//#define UART_UFCR_RFDIV UART_UFCR_RFDIV_4
|
|
//#define UART_UFCR_RFDIV UART_UFCR_RFDIV_7
|
|
|
|
uint32_t uart_get_reffreq(uint32_t instance)
|
|
{
|
|
uint32_t div = UART_UFCR_RFDIV;
|
|
uint32_t ret = 0;
|
|
uint32_t freq = get_peri_clock(UART_MODULE_CLK(instance));
|
|
|
|
if (div == BF_UART_UFCR_RFDIV(4))
|
|
ret = freq / 2;
|
|
else if (div == BF_UART_UFCR_RFDIV(2))
|
|
ret = freq / 4;
|
|
else if (div == BF_UART_UFCR_RFDIV(6))
|
|
ret = freq / 7;
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint8_t uart_putchar(uint32_t instance, uint8_t * ch)
|
|
{
|
|
/* Wait for Tx FIFO not full */
|
|
while (HW_UART_UTS(instance).B.TXFULL);
|
|
|
|
HW_UART_UTXD_WR(instance, *ch);
|
|
|
|
return *ch;
|
|
}
|
|
|
|
uint8_t uart_getchar(uint32_t instance)
|
|
{
|
|
uint32_t read_data;
|
|
|
|
/* If Rx FIFO has no data ready */
|
|
if (!(HW_UART_USR2(instance).B.RDR))
|
|
return NONE_CHAR;
|
|
|
|
read_data = HW_UART_URXD_RD(instance);
|
|
|
|
/* If error are detected */
|
|
if (read_data & 0x7C00)
|
|
return NONE_CHAR;
|
|
|
|
return (uint8_t) read_data;
|
|
}
|
|
|
|
void uart_set_FIFO_mode(uint32_t instance, uint8_t fifo, uint8_t trigger_level,
|
|
uint8_t service_mode)
|
|
{
|
|
if (fifo == TX_FIFO) {
|
|
/* Configure the TX_FIFO trigger level */
|
|
HW_UART_UFCR_CLR(instance,BM_UART_UFCR_TXTL);
|
|
HW_UART_UFCR_SET(instance, BF_UART_UFCR_TXTL(trigger_level));
|
|
/* Configure the TX_FIFO service mode */
|
|
/* Default mode is polling: IRQ and DMA requests are disabled */
|
|
HW_UART_UCR1_CLR(instance,(BM_UART_UCR1_TRDYEN | BM_UART_UCR1_TXDMAEN));
|
|
if (service_mode == DMA_MODE)
|
|
HW_UART_UCR1_SET(instance,BM_UART_UCR1_TXDMAEN);
|
|
else if (service_mode == IRQ_MODE)
|
|
HW_UART_UCR1_SET(instance,BM_UART_UCR1_TRDYEN);
|
|
} else { /* fifo = RX_FIFO */
|
|
/* Configure the RX_FIFO trigger level */
|
|
HW_UART_UFCR_CLR(instance,BM_UART_UFCR_RXTL);
|
|
HW_UART_UFCR_SET(instance,BF_UART_UFCR_RXTL(trigger_level));
|
|
/* Configure the RX_FIFO service mode */
|
|
/* Default mode is polling: IRQ and DMA requests are disabled */
|
|
HW_UART_UCR1_CLR(instance,(BM_UART_UCR1_RRDYEN | BM_UART_UCR1_RXDMAEN));
|
|
if (service_mode == DMA_MODE)
|
|
HW_UART_UCR1_SET(instance,BM_UART_UCR1_RXDMAEN);
|
|
else if (service_mode == IRQ_MODE)
|
|
HW_UART_UCR1_SET(instance,BM_UART_UCR1_RRDYEN);
|
|
}
|
|
}
|
|
|
|
void uart_set_loopback_mode(uint32_t instance, uint8_t state)
|
|
{
|
|
if (state == TRUE)
|
|
HW_UART_UTS_SET(instance, BM_UART_UTS_LOOP);
|
|
else
|
|
HW_UART_UTS_CLR(instance, BM_UART_UTS_LOOP);
|
|
}
|
|
|
|
void uart_setup_interrupt(uint32_t instance, void (*irq_subroutine)(void), uint8_t state)
|
|
{
|
|
uint32_t irq_id = UART_IRQS(instance);
|
|
|
|
if (state == TRUE) {
|
|
/* register the IRQ sub-routine */
|
|
register_interrupt_routine(irq_id, irq_subroutine);
|
|
/* enable the IRQ */
|
|
enable_interrupt(irq_id, CPU_0, 0);
|
|
} else
|
|
/* disable the IRQ */
|
|
disable_interrupt(irq_id, CPU_0);
|
|
}
|
|
|
|
void uart_init(uint32_t instance, uint32_t baudrate, uint8_t parity,
|
|
uint8_t stopbits, uint8_t datasize, uint8_t flowcontrol)
|
|
{
|
|
uint32_t base = REGS_UART_BASE(instance);
|
|
|
|
/* configure the I/O for the port */
|
|
uart_iomux_config(instance);
|
|
|
|
/* enable the source clocks to the UART port */
|
|
clock_gating_config(base, CLOCK_ON);
|
|
|
|
/* Wait for UART to finish transmitting before changing the configuration */
|
|
while (!(HW_UART_UTS(instance).B.TXEMPTY)) ;
|
|
|
|
/* Disable UART */
|
|
HW_UART_UCR1_CLR(instance,BM_UART_UCR1_UARTEN );
|
|
|
|
/* Configure FIFOs trigger level to half-full and half-empty */
|
|
HW_UART_UFCR_WR(instance, BF_UART_UFCR_RXTL(16) | UART_UFCR_RFDIV | BF_UART_UFCR_TXTL(16));
|
|
|
|
/* Setup One Millisecond timer */
|
|
HW_UART_ONEMS_WR(instance, uart_get_reffreq(instance) / 1000);
|
|
|
|
/* Set parity */
|
|
if (parity == PARITY_NONE)
|
|
HW_UART_UCR2_CLR(instance,(BM_UART_UCR2_PREN| BM_UART_UCR2_PROE));
|
|
else if (parity == PARITY_ODD)
|
|
HW_UART_UCR2_SET(instance,(BM_UART_UCR2_PREN| BM_UART_UCR2_PROE));
|
|
else { /* parity == PARITY_EVEN */
|
|
HW_UART_UCR2_SET(instance, BM_UART_UCR2_PREN);
|
|
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_PROE);
|
|
}
|
|
|
|
/* Set stop bit */
|
|
if (stopbits == STOPBITS_ONE)
|
|
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_STPB);
|
|
else /* stopbits == STOPBITS_TWO */
|
|
HW_UART_UCR2_SET(instance, BM_UART_UCR2_STPB);
|
|
|
|
/* Set data size */
|
|
if (datasize == EIGHTBITS)
|
|
HW_UART_UCR2_SET(instance, BM_UART_UCR2_WS);
|
|
else /* stopbits == STOPBITS_TWO */
|
|
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_WS);
|
|
|
|
/* Configure the flow control */
|
|
if (flowcontrol == FLOWCTRL_ON) {
|
|
/* transmit done when RTS asserted */
|
|
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_IRTS );
|
|
/* CTS controlled by the receiver */
|
|
HW_UART_UCR2_SET(instance, BM_UART_UCR2_CTSC );
|
|
} else { /* flowcontrol == FLOWCTRL_OFF */
|
|
/* Ignore RTS */
|
|
HW_UART_UCR2_SET(instance, BM_UART_UCR2_IRTS);
|
|
/* CTS controlled by the CTS bit */
|
|
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_CTSC);
|
|
}
|
|
|
|
/* the reference manual says that this bit must always be set */
|
|
HW_UART_UCR3_SET(instance, BM_UART_UCR3_RXDMUXSEL);
|
|
|
|
/* Enable UART */
|
|
HW_UART_UCR1_SET(instance, BM_UART_UCR1_UARTEN);
|
|
|
|
/* Enable FIFOs and does software reset to clear status flags, reset
|
|
the transmit and receive state machine, and reset the FIFOs */
|
|
HW_UART_UCR2_SET(instance, BM_UART_UCR2_TXEN | BM_UART_UCR2_RXEN | BM_UART_UCR2_SRST);
|
|
|
|
/* Set the numerator value minus one of the BRM ratio */
|
|
HW_UART_UBIR_WR(instance, (baudrate / 100) - 1);
|
|
|
|
/* Set the denominator value minus one of the BRM ratio */
|
|
HW_UART_UBMR_WR(instance, ((uart_get_reffreq(instance) / 1600) - 1));
|
|
|
|
/* Optional: prevent the UART to enter debug state. Useful when debugging
|
|
the code with a JTAG and without active IRQ */
|
|
HW_UART_UTS_SET(instance, BM_UART_UTS_DBGEN);
|
|
}
|
|
|