rt-thread/bsp/lpc408x/drivers/drv_uart.c

349 lines
7.4 KiB
C

/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-05-18 Bernard The first version for LPC40xx
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include "board.h"
struct lpc_uart
{
LPC_UART_TypeDef *UART;
IRQn_Type UART_IRQn;
};
static rt_err_t lpc_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
struct lpc_uart *uart;
uint32_t Fdiv = 0;
RT_ASSERT(serial != RT_NULL);
uart = (struct lpc_uart *)serial->parent.user_data;
/* Initialize UART Configuration parameter structure to default state:
* Baudrate = 115200 bps
* 8 data bit
* 1 Stop bit
* None parity
*/
/* set DLAB=1 */
uart->UART->LCR |= 0x80;
/* config uart baudrate */
Fdiv = (PeripheralClock / 16) / cfg->baud_rate;
uart->UART->DLM = Fdiv / 256;
uart->UART->DLL = Fdiv % 256;
/* set DLAB=0 */
uart->UART->LCR &= ~0x80;
/* config to 8 data bit,1 Stop bit,None parity */
uart->UART->LCR |= 0x03;
/*enable and reset FIFO*/
uart->UART->FCR = 0x07;
return RT_EOK;
}
static rt_err_t lpc_control(struct rt_serial_device *serial, int cmd, void *arg)
{
struct lpc_uart *uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct lpc_uart *)serial->parent.user_data;
switch (cmd)
{
case RT_DEVICE_CTRL_CLR_INT:
/* disable rx irq */
uart->UART->IER &= ~0x01;
break;
case RT_DEVICE_CTRL_SET_INT:
/* enable rx irq */
uart->UART->IER |= 0x01;
break;
}
return RT_EOK;
}
static int lpc_putc(struct rt_serial_device *serial, char c)
{
struct lpc_uart *uart;
uart = (struct lpc_uart *)serial->parent.user_data;
while (!(uart->UART->LSR & 0x20));
uart->UART->THR = c;
return 1;
}
static int lpc_getc(struct rt_serial_device *serial)
{
struct lpc_uart *uart;
uart = (struct lpc_uart *)serial->parent.user_data;
if (uart->UART->LSR & 0x01)
return (uart->UART->RBR);
else
return -1;
}
static const struct rt_uart_ops lpc_uart_ops =
{
lpc_configure,
lpc_control,
lpc_putc,
lpc_getc,
};
#ifdef RT_USING_UART0
/* UART0 device driver structure */
#if RTTHREAD_VERSION < 20000 /* RT-Thread 1.x */
struct serial_ringbuffer uart0_int_rx;
#endif
struct lpc_uart uart0 =
{
LPC_UART0,
UART0_IRQn,
};
struct rt_serial_device serial0;
void UART0_IRQHandler(void)
{
volatile uint32_t IIR, tmp;
/* enter interrupt */
rt_interrupt_enter();
IIR = LPC_UART0->IIR;
IIR &= 0x0e;
switch (IIR)
{
case 0x04:
case 0x0C:
#if RTTHREAD_VERSION < 20000
rt_hw_serial_isr(&serial0);
#else
rt_hw_serial_isr(&serial0, RT_SERIAL_EVENT_RX_IND);
#endif
break;
case 0x06:
tmp = LPC_UART0->LSR;
break;
default :
tmp = LPC_UART0->LSR;
break;
}
/* leave interrupt */
rt_interrupt_leave();
}
#endif
#ifdef RT_USING_UART2
/* UART2 device driver structure */
#if RTTHREAD_VERSION < 20000 /* RT-Thread 1.x */
struct serial_ringbuffer uart2_int_rx;
#endif
struct lpc_uart uart2 =
{
LPC_UART2,
UART2_IRQn,
};
struct rt_serial_device serial2;
void UART2_IRQHandler(void)
{
volatile uint32_t IIR, tmp;
/* enter interrupt */
rt_interrupt_enter();
IIR = LPC_UART2->IIR;
IIR &= 0x0e;
switch (IIR)
{
case 0x04:
case 0x0C:
#if RTTHREAD_VERSION < 20000
rt_hw_serial_isr(&serial2);
#else
rt_hw_serial_isr(&serial2, RT_SERIAL_EVENT_RX_IND);
#endif
break;
case 0x06:
tmp = LPC_UART2->LSR;
break;
default :
tmp = LPC_UART2->LSR;
break;
}
/* leave interrupt */
rt_interrupt_leave();
}
#endif
#ifdef RT_USING_UART4
/* UART4 device driver structure */
#if RTTHREAD_VERSION < 20000 /* RT-Thread 1.x */
struct serial_ringbuffer uart4_int_rx;
#endif
struct lpc_uart uart4 =
{
LPC_UART4,
UART4_IRQn,
};
struct rt_serial_device serial4;
void UART4_IRQHandler(void)
{
volatile uint32_t IIR, tmp;
/* enter interrupt */
rt_interrupt_enter();
IIR = LPC_UART4->IIR;
IIR &= 0x0e;
switch (IIR)
{
case 0x04:
case 0x0C:
#if RTTHREAD_VERSION < 20000
rt_hw_serial_isr(&serial4);
#else
rt_hw_serial_isr(&serial4, RT_SERIAL_EVENT_RX_IND);
#endif
break;
case 0x06:
tmp = LPC_UART4->LSR;
break;
default :
tmp = LPC_UART4->LSR;
break;
}
/* leave interrupt */
rt_interrupt_leave();
}
#endif
void rt_hw_uart_init(void)
{
struct lpc_uart *uart;
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
#ifdef RT_USING_UART0
uart = &uart0;
serial0.ops = &lpc_uart_ops;
serial0.config = config;
#if RTTHREAD_VERSION < 20000
serial0.int_rx = &uart0_int_rx;
#endif
serial0.parent.user_data = uart;
/*
* Initialize UART0 pin connect
* P0.2: U0_TXD
* P0.3: U0_RXD
*/
LPC_IOCON->P0_2 &= ~0x07;
LPC_IOCON->P0_2 |= 0x01;
LPC_IOCON->P0_3 &= ~0x07;
LPC_IOCON->P0_3 |= 0x01;
/* enable the uart0 power and clock */
LPC_SC->PCONP |= 0x01 << 3;
/* preemption = 1, sub-priority = 1 */
NVIC_SetPriority(uart->UART_IRQn, ((0x01 << 3) | 0x01));
/* Enable Interrupt for UART channel */
NVIC_EnableIRQ(uart->UART_IRQn);
/* register UART0 device */
rt_hw_serial_register(&serial0, "uart0",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
uart);
#endif
#ifdef RT_USING_UART2
uart = &uart2;
serial2.ops = &lpc_uart_ops;
serial2.config = config;
#if RTTHREAD_VERSION < 20000
serial2.int_rx = &uart2_int_rx;
#endif
serial2.parent.user_data = uart;
/*
* Initialize UART2 pin connect
* P2.8: U2_TXD
* P0.11: U2_RXD
*/
LPC_IOCON->P2_8 &= ~0x07;
LPC_IOCON->P0_11 &= ~0x07;
LPC_IOCON->P2_8 |= 0x02;
LPC_IOCON->P0_11 |= 0x01;
/* enable the uart2 power and clock */
LPC_SC->PCONP |= 0x01 << 24;
/* preemption = 1, sub-priority = 1 */
NVIC_SetPriority(uart->UART_IRQn, ((0x01 << 3) | 0x01));
/* Enable Interrupt for UART channel */
NVIC_EnableIRQ(uart->UART_IRQn);
/* register UART2 device */
rt_hw_serial_register(&serial2, "uart2",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
uart);
#endif
#ifdef RT_USING_UART4
uart = &uart4;
serial4.ops = &lpc_uart_ops;
serial4.config = config;
#if RTTHREAD_VERSION < 20000
serial4.int_rx = &uart4_int_rx;
#endif
serial4.parent.user_data = uart;
/*
* Initialize UART2 pin connect
* P5.4: U2_TXD
* P5.3: U2_RXD
*/
LPC_IOCON->P5_4 &= ~0x07;
LPC_IOCON->P5_3 &= ~0x07;
LPC_IOCON->P5_4 |= 0x04;
LPC_IOCON->P5_3 |= 0x04;
/* enable the uart4 power and clock */
LPC_SC->PCONP |= 0x01 << 8;
/* preemption = 1, sub-priority = 1 */
NVIC_SetPriority(uart->UART_IRQn, ((0x01 << 3) | 0x01));
/* Enable Interrupt for UART channel */
NVIC_EnableIRQ(uart->UART_IRQn);
/* register UART2 device */
rt_hw_serial_register(&serial4, "uart4",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
uart);
#endif
}