summaryrefslogtreecommitdiff
path: root/bsp/nxp/lpc/lpc1114/driver/drv_uart.c
blob: f7a7320b54b16e3e328ff9c98fa88fdcf62dacf4 (plain)
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
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2013-05-18     Bernard      The first version for LPC40xx
 * 2019-05-05     jg1uaa       port to LPC1114
 */
#include <stddef.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <rthw.h>
#include "board.h"      // CPU_CLOCK
#include "drv_uart.h"

#ifdef BSP_USING_SERIAL

#define UART_BASE       0x40008000              // UART (only one)
#define UART_IRQ        21
#define UART_CLOCK      (CPU_CLOCK / 1)         // Hz

#define URBR            HWREG32(UART_BASE + 0x00)       // R-
#define UTHR            HWREG32(UART_BASE + 0x00)       // -W
#define UIER            HWREG32(UART_BASE + 0x04)       // RW
#define UIIR            HWREG32(UART_BASE + 0x08)       // R-
#define UFCR            HWREG32(UART_BASE + 0x08)       // -W
#define ULCR            HWREG32(UART_BASE + 0x0c)       // RW
#define UMCR            HWREG32(UART_BASE + 0x10)       // RW
#define ULSR            HWREG32(UART_BASE + 0x14)       // R-
#define UMSR            HWREG32(UART_BASE + 0x18)       // R-

#define UDLL            HWREG32(UART_BASE + 0x00)       // RW
#define UDLM            HWREG32(UART_BASE + 0x04)       // RW

#define IOCONFIG_BASE   0x40044000
#define IOCON_PIO1_6    HWREG32(IOCONFIG_BASE + 0xa4)
#define IOCON_PIO1_7    HWREG32(IOCONFIG_BASE + 0xa8)

#define SYSCON_BASE     0x40048000
#define AHBCLKCTRL      HWREG32(SYSCON_BASE + 0x80)
#define UARTCLKDIV      HWREG32(SYSCON_BASE + 0x98)

static rt_err_t lpc_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
    rt_uint32_t Fdiv = 0;

    RT_ASSERT(serial != RT_NULL);

    /* Initialize UART Configuration parameter structure to default state:
     * Baudrate = 115200 bps
     * 8 data bit
     * 1 Stop bit
     * None parity
     */
    /* set DLAB=1 */
    ULCR |= 0x80;
    /* config uart baudrate */
    Fdiv = UART_CLOCK / (cfg->baud_rate * 16);
    UDLM = Fdiv / 256;
    UDLL = Fdiv % 256;
    /* set DLAB=0 */
    ULCR &= ~0x80;
    /* config to 8 data bit,1 Stop bit,None parity */
    ULCR |= 0x03;

    /*enable and reset FIFO*/
    UFCR = 0x07;

    return RT_EOK;
}

static rt_err_t lpc_control(struct rt_serial_device *serial, int cmd, void *arg)
{
    RT_ASSERT(serial != RT_NULL);

    switch (cmd)
    {
    case RT_DEVICE_CTRL_CLR_INT:
        /* disable rx irq */
        UIER &= ~0x01;
        break;
    case RT_DEVICE_CTRL_SET_INT:
        /* enable rx irq */
        UIER |= 0x01;
        break;
    }

    return RT_EOK;
}

static int lpc_putc(struct rt_serial_device *serial, char c)
{
    while (!(ULSR & 0x20));
    UTHR = c;

    return 1;
}

static int lpc_getc(struct rt_serial_device *serial)
{
    if (ULSR & 0x01)
        return URBR;
    else
        return -1;
}

static const struct rt_uart_ops lpc_uart_ops =
{
    lpc_configure,
    lpc_control,
    lpc_putc,
    lpc_getc,
};

struct rt_serial_device serial;

void UART_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    switch (UIIR & 0x0e)
    {
    case 0x04:
    case 0x0C:
        rt_hw_serial_isr(&serial, RT_SERIAL_EVENT_RX_IND);
        break;
    case 0x06:
        (void)ULSR;
        break;
    default:
        (void)ULSR;
        break;
    }
    /* leave interrupt */
    rt_interrupt_leave();
}

int rt_hw_uart_init(void)
{
    rt_err_t ret = RT_EOK;
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;

    serial.ops    = &lpc_uart_ops;
    serial.config = config;
    serial.parent.user_data = NULL;

    /*
     * Initialize UART pin connect
     * P1.6: U0_RXD
     * P1.7: U0_TXD
     */
    IOCON_PIO1_6 = 0xc1;
    IOCON_PIO1_7 = 0xc1;

    /* setup the uart power and clock */
    UARTCLKDIV = 0x01;          // UART PCLK = system clock / 1
    AHBCLKCTRL |= (1 << 12);    // UART power-up

    /* priority = 1 */
    NVIC_SetPriority(UART_IRQ, 0x01 << 6);

    /* Enable Interrupt for UART channel */
    NVIC_EnableIRQ(UART_IRQ);

    /* register UART device */
    ret = rt_hw_serial_register(&serial, "uart",
                                RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
                                NULL);

    return ret;
}
INIT_BOARD_EXPORT(rt_hw_uart_init);

#endif /* BSP_USING_SERIAL */