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 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "board.h"
14
15 #ifdef RT_USING_SERIAL
16
17 struct lpc_uart
18 {
19 LPC_UART_TypeDef *UART;
20 IRQn_Type UART_IRQn;
21 };
22
lpc_configure(struct rt_serial_device * serial,struct serial_configure * cfg)23 static rt_err_t lpc_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
24 {
25 struct lpc_uart *uart;
26 uint32_t Fdiv = 0;
27
28 RT_ASSERT(serial != RT_NULL);
29 uart = (struct lpc_uart *)serial->parent.user_data;
30
31 /* Initialize UART Configuration parameter structure to default state:
32 * Baudrate = 115200 bps
33 * 8 data bit
34 * 1 Stop bit
35 * None parity
36 */
37 /* set DLAB=1 */
38 uart->UART->LCR |= 0x80;
39 /* config uart baudrate */
40 Fdiv = (PeripheralClock / 16) / cfg->baud_rate;
41 uart->UART->DLM = Fdiv / 256;
42 uart->UART->DLL = Fdiv % 256;
43 /* set DLAB=0 */
44 uart->UART->LCR &= ~0x80;
45 /* config to 8 data bit,1 Stop bit,None parity */
46 uart->UART->LCR |= 0x03;
47
48 /*enable and reset FIFO*/
49 uart->UART->FCR = 0x07;
50
51 return RT_EOK;
52 }
53
lpc_control(struct rt_serial_device * serial,int cmd,void * arg)54 static rt_err_t lpc_control(struct rt_serial_device *serial, int cmd, void *arg)
55 {
56 struct lpc_uart *uart;
57
58 RT_ASSERT(serial != RT_NULL);
59 uart = (struct lpc_uart *)serial->parent.user_data;
60
61 switch (cmd)
62 {
63 case RT_DEVICE_CTRL_CLR_INT:
64 /* disable rx irq */
65 uart->UART->IER &= ~0x01;
66 break;
67 case RT_DEVICE_CTRL_SET_INT:
68 /* enable rx irq */
69 uart->UART->IER |= 0x01;
70 break;
71 }
72
73 return RT_EOK;
74 }
75
lpc_putc(struct rt_serial_device * serial,char c)76 static int lpc_putc(struct rt_serial_device *serial, char c)
77 {
78 struct lpc_uart *uart;
79
80 uart = (struct lpc_uart *)serial->parent.user_data;
81 while (!(uart->UART->LSR & 0x20));
82 uart->UART->THR = c;
83
84 return 1;
85 }
86
lpc_getc(struct rt_serial_device * serial)87 static int lpc_getc(struct rt_serial_device *serial)
88 {
89 struct lpc_uart *uart;
90
91 uart = (struct lpc_uart *)serial->parent.user_data;
92 if (uart->UART->LSR & 0x01)
93 return (uart->UART->RBR);
94 else
95 return -1;
96 }
97
98 static const struct rt_uart_ops lpc_uart_ops =
99 {
100 lpc_configure,
101 lpc_control,
102 lpc_putc,
103 lpc_getc,
104 };
105
106 #ifdef BSP_USING_UART0
107
108 struct lpc_uart uart0 =
109 {
110 LPC_UART0,
111 UART0_IRQn,
112 };
113 struct rt_serial_device serial0;
114
UART0_IRQHandler(void)115 void UART0_IRQHandler(void)
116 {
117 volatile uint32_t IIR, tmp;
118
119 /* enter interrupt */
120 rt_interrupt_enter();
121
122 IIR = LPC_UART0->IIR;
123 IIR &= 0x0e;
124 switch (IIR)
125 {
126 case 0x04:
127 case 0x0C:
128 rt_hw_serial_isr(&serial0, RT_SERIAL_EVENT_RX_IND);
129 break;
130 case 0x06:
131 tmp = LPC_UART0->LSR;
132 break;
133 default :
134 tmp = LPC_UART0->LSR;
135 break;
136 }
137 /* leave interrupt */
138 rt_interrupt_leave();
139 }
140 #endif
141
142 #ifdef BSP_USING_UART2
143
144 struct lpc_uart uart2 =
145 {
146 LPC_UART2,
147 UART2_IRQn,
148 };
149 struct rt_serial_device serial2;
150
UART2_IRQHandler(void)151 void UART2_IRQHandler(void)
152 {
153 volatile uint32_t IIR, tmp;
154
155 /* enter interrupt */
156 rt_interrupt_enter();
157
158 IIR = LPC_UART2->IIR;
159 IIR &= 0x0e;
160 switch (IIR)
161 {
162 case 0x04:
163 case 0x0C:
164 rt_hw_serial_isr(&serial2, RT_SERIAL_EVENT_RX_IND);
165 break;
166 case 0x06:
167 tmp = LPC_UART2->LSR;
168 break;
169 default :
170 tmp = LPC_UART2->LSR;
171 break;
172 }
173
174 /* leave interrupt */
175 rt_interrupt_leave();
176 }
177 #endif
178
rt_hw_uart_init(void)179 int rt_hw_uart_init(void)
180 {
181 rt_err_t ret = RT_EOK;
182 struct lpc_uart *uart;
183 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
184
185 #ifdef BSP_USING_UART0
186 uart = &uart0;
187
188 serial0.ops = &lpc_uart_ops;
189 serial0.config = config;
190 serial0.parent.user_data = uart;
191
192 /*
193 * Initialize UART0 pin connect
194 * P0.2: U0_TXD
195 * P0.3: U0_RXD
196 */
197 LPC_IOCON->P0_2 &= ~0x07;
198 LPC_IOCON->P0_2 |= 0x01;
199 LPC_IOCON->P0_3 &= ~0x07;
200 LPC_IOCON->P0_3 |= 0x01;
201
202 /* enable the uart0 power and clock */
203 LPC_SC->PCONP |= 0x01 << 3;
204
205 /* preemption = 1, sub-priority = 1 */
206 NVIC_SetPriority(uart->UART_IRQn, ((0x01 << 3) | 0x01));
207
208 /* Enable Interrupt for UART channel */
209 NVIC_EnableIRQ(uart->UART_IRQn);
210
211 /* register UART0 device */
212 ret = rt_hw_serial_register(&serial0, "uart0",
213 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
214 uart);
215 #endif
216
217 #ifdef BSP_USING_UART2
218 uart = &uart2;
219
220 serial2.ops = &lpc_uart_ops;
221 serial2.config = config;
222 serial2.parent.user_data = uart;
223
224 /*
225 * Initialize UART2 pin connect
226 * P2.8: U2_TXD
227 * P0.11: U2_RXD
228 */
229 LPC_IOCON->P2_8 &= ~0x07;
230 LPC_IOCON->P0_11 &= ~0x07;
231 LPC_IOCON->P2_8 |= 0x02;
232 LPC_IOCON->P0_11 |= 0x01;
233
234 /* enable the uart2 power and clock */
235 LPC_SC->PCONP |= 0x01 << 24;
236 /* preemption = 1, sub-priority = 1 */
237 NVIC_SetPriority(uart->UART_IRQn, ((0x01 << 3) | 0x01));
238
239 /* Enable Interrupt for UART channel */
240 NVIC_EnableIRQ(uart->UART_IRQn);
241
242 /* register UART2 device */
243 ret = rt_hw_serial_register(&serial2, "uart2",
244 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
245 uart);
246 #endif
247
248 return ret;
249 }
250 INIT_BOARD_EXPORT(rt_hw_uart_init);
251
252 #endif /* RT_USING_SERIAL */
253