1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2013-05-18 Bernard The first version for LPC40xx
9 * 2019-05-05 jg1uaa port to LPC1114
10 */
11 #include <stddef.h>
12 #include <rtthread.h>
13 #include <rtdevice.h>
14 #include <rthw.h>
15 #include "board.h" // CPU_CLOCK
16 #include "drv_uart.h"
17
18 #ifdef BSP_USING_SERIAL
19
20 #define UART_BASE 0x40008000 // UART (only one)
21 #define UART_IRQ 21
22 #define UART_CLOCK (CPU_CLOCK / 1) // Hz
23
24 #define URBR HWREG32(UART_BASE + 0x00) // R-
25 #define UTHR HWREG32(UART_BASE + 0x00) // -W
26 #define UIER HWREG32(UART_BASE + 0x04) // RW
27 #define UIIR HWREG32(UART_BASE + 0x08) // R-
28 #define UFCR HWREG32(UART_BASE + 0x08) // -W
29 #define ULCR HWREG32(UART_BASE + 0x0c) // RW
30 #define UMCR HWREG32(UART_BASE + 0x10) // RW
31 #define ULSR HWREG32(UART_BASE + 0x14) // R-
32 #define UMSR HWREG32(UART_BASE + 0x18) // R-
33
34 #define UDLL HWREG32(UART_BASE + 0x00) // RW
35 #define UDLM HWREG32(UART_BASE + 0x04) // RW
36
37 #define IOCONFIG_BASE 0x40044000
38 #define IOCON_PIO1_6 HWREG32(IOCONFIG_BASE + 0xa4)
39 #define IOCON_PIO1_7 HWREG32(IOCONFIG_BASE + 0xa8)
40
41 #define SYSCON_BASE 0x40048000
42 #define AHBCLKCTRL HWREG32(SYSCON_BASE + 0x80)
43 #define UARTCLKDIV HWREG32(SYSCON_BASE + 0x98)
44
lpc_configure(struct rt_serial_device * serial,struct serial_configure * cfg)45 static rt_err_t lpc_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
46 {
47 rt_uint32_t Fdiv = 0;
48
49 RT_ASSERT(serial != RT_NULL);
50
51 /* Initialize UART Configuration parameter structure to default state:
52 * Baudrate = 115200 bps
53 * 8 data bit
54 * 1 Stop bit
55 * None parity
56 */
57 /* set DLAB=1 */
58 ULCR |= 0x80;
59 /* config uart baudrate */
60 Fdiv = UART_CLOCK / (cfg->baud_rate * 16);
61 UDLM = Fdiv / 256;
62 UDLL = Fdiv % 256;
63 /* set DLAB=0 */
64 ULCR &= ~0x80;
65 /* config to 8 data bit,1 Stop bit,None parity */
66 ULCR |= 0x03;
67
68 /*enable and reset FIFO*/
69 UFCR = 0x07;
70
71 return RT_EOK;
72 }
73
lpc_control(struct rt_serial_device * serial,int cmd,void * arg)74 static rt_err_t lpc_control(struct rt_serial_device *serial, int cmd, void *arg)
75 {
76 RT_ASSERT(serial != RT_NULL);
77
78 switch (cmd)
79 {
80 case RT_DEVICE_CTRL_CLR_INT:
81 /* disable rx irq */
82 UIER &= ~0x01;
83 break;
84 case RT_DEVICE_CTRL_SET_INT:
85 /* enable rx irq */
86 UIER |= 0x01;
87 break;
88 }
89
90 return RT_EOK;
91 }
92
lpc_putc(struct rt_serial_device * serial,char c)93 static int lpc_putc(struct rt_serial_device *serial, char c)
94 {
95 while (!(ULSR & 0x20));
96 UTHR = c;
97
98 return 1;
99 }
100
lpc_getc(struct rt_serial_device * serial)101 static int lpc_getc(struct rt_serial_device *serial)
102 {
103 if (ULSR & 0x01)
104 return URBR;
105 else
106 return -1;
107 }
108
109 static const struct rt_uart_ops lpc_uart_ops =
110 {
111 lpc_configure,
112 lpc_control,
113 lpc_putc,
114 lpc_getc,
115 };
116
117 struct rt_serial_device serial;
118
UART_IRQHandler(void)119 void UART_IRQHandler(void)
120 {
121 /* enter interrupt */
122 rt_interrupt_enter();
123
124 switch (UIIR & 0x0e)
125 {
126 case 0x04:
127 case 0x0C:
128 rt_hw_serial_isr(&serial, RT_SERIAL_EVENT_RX_IND);
129 break;
130 case 0x06:
131 (void)ULSR;
132 break;
133 default:
134 (void)ULSR;
135 break;
136 }
137 /* leave interrupt */
138 rt_interrupt_leave();
139 }
140
rt_hw_uart_init(void)141 int rt_hw_uart_init(void)
142 {
143 rt_err_t ret = RT_EOK;
144 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
145
146 serial.ops = &lpc_uart_ops;
147 serial.config = config;
148 serial.parent.user_data = NULL;
149
150 /*
151 * Initialize UART pin connect
152 * P1.6: U0_RXD
153 * P1.7: U0_TXD
154 */
155 IOCON_PIO1_6 = 0xc1;
156 IOCON_PIO1_7 = 0xc1;
157
158 /* setup the uart power and clock */
159 UARTCLKDIV = 0x01; // UART PCLK = system clock / 1
160 AHBCLKCTRL |= (1 << 12); // UART power-up
161
162 /* priority = 1 */
163 NVIC_SetPriority(UART_IRQ, 0x01 << 6);
164
165 /* Enable Interrupt for UART channel */
166 NVIC_EnableIRQ(UART_IRQ);
167
168 /* register UART device */
169 ret = rt_hw_serial_register(&serial, "uart",
170 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
171 NULL);
172
173 return ret;
174 }
175 INIT_BOARD_EXPORT(rt_hw_uart_init);
176
177 #endif /* BSP_USING_SERIAL */
178