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 * 2010-03-08 Bernard The first version for LPC17xx
9 * 2010-05-02 Aozima update CMSIS to 130
10 */
11
12 #include <rthw.h>
13 #include <rtthread.h>
14 #include "LPC17xx.h"
15
16 #define IER_RBR 0x01
17 #define IER_THRE 0x02
18 #define IER_RLS 0x04
19
20 #define IIR_PEND 0x01
21 #define IIR_RLS 0x03
22 #define IIR_RDA 0x02
23 #define IIR_CTI 0x06
24 #define IIR_THRE 0x01
25
26 #define LSR_RDR 0x01
27 #define LSR_OE 0x02
28 #define LSR_PE 0x04
29 #define LSR_FE 0x08
30 #define LSR_BI 0x10
31 #define LSR_THRE 0x20
32 #define LSR_TEMT 0x40
33 #define LSR_RXFE 0x80
34
35 /**
36 * @addtogroup LPC176x
37 */
38
39 /*@{*/
40 #if defined(RT_USING_UART0) && defined(RT_USING_DEVICE)
41
42 #define UART_BAUDRATE 115200
43 #define LPC_UART LPC_UART0
44 #define UART_IRQn UART0_IRQn
45
46 struct rt_uart_lpc
47 {
48 struct rt_device parent;
49
50 /* buffer for reception */
51 rt_uint8_t read_index, save_index;
52 rt_uint8_t rx_buffer[RT_UART_RX_BUFFER_SIZE];
53 } uart_device;
54
UART0_IRQHandler(void)55 void UART0_IRQHandler(void)
56 {
57 rt_ubase_t level, iir;
58 struct rt_uart_lpc *uart = &uart_device;
59 /* enter interrupt */
60 rt_interrupt_enter();
61 /* read IIR and clear it */
62 iir = LPC_UART->IIR;
63
64 iir >>= 1; /* skip pending bit in IIR */
65 iir &= 0x07; /* check bit 1~3, interrupt identification */
66
67 if (iir == IIR_RDA) /* Receive Data Available */
68 {
69 /* Receive Data Available */
70 uart->rx_buffer[uart->save_index] = LPC_UART->RBR;
71
72 level = rt_hw_interrupt_disable();
73 uart->save_index ++;
74 if (uart->save_index >= RT_UART_RX_BUFFER_SIZE)
75 uart->save_index = 0;
76 rt_hw_interrupt_enable(level);
77
78 /* invoke callback */
79 if (uart->parent.rx_indicate != RT_NULL)
80 {
81 rt_size_t length;
82 if (uart->read_index > uart->save_index)
83 length = RT_UART_RX_BUFFER_SIZE - uart->read_index + uart->save_index;
84 else
85 length = uart->save_index - uart->read_index;
86
87 uart->parent.rx_indicate(&uart->parent, length);
88 }
89 }
90 else if (iir == IIR_RLS)
91 {
92 iir = LPC_UART->LSR; //oe pe fe oe read for clear interrupt
93 }
94 /* leave interrupt */
95 rt_interrupt_leave();
96 return;
97 }
98
rt_uart_init(rt_device_t dev)99 static rt_err_t rt_uart_init(rt_device_t dev)
100 {
101 rt_uint32_t Fdiv;
102 rt_uint32_t pclkdiv, pclk;
103
104 /* Init UART Hardware */
105 if (LPC_UART == LPC_UART0)
106 {
107 LPC_PINCON->PINSEL0 &= ~0x000000F0;
108 LPC_PINCON->PINSEL0 |= 0x00000050; /* RxD0 is P0.3 and TxD0 is P0.2 */
109 /* By default, the PCLKSELx value is zero, thus, the PCLK for
110 all the peripherals is 1/4 of the SystemFrequency. */
111 /* Bit 6~7 is for UART0 */
112 pclkdiv = (LPC_SC->PCLKSEL0 >> 6) & 0x03;
113 switch (pclkdiv)
114 {
115 case 0x00:
116 default:
117 pclk = SystemCoreClock / 4;
118 break;
119 case 0x01:
120 pclk = SystemCoreClock;
121 break;
122 case 0x02:
123 pclk = SystemCoreClock / 2;
124 break;
125 case 0x03:
126 pclk = SystemCoreClock / 8;
127 break;
128 }
129
130 LPC_UART0->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
131 Fdiv = (pclk / 16) / UART_BAUDRATE; /*baud rate */
132 LPC_UART0->DLM = Fdiv / 256;
133 LPC_UART0->DLL = Fdiv % 256;
134 LPC_UART0->LCR = 0x03; /* DLAB = 0 */
135 LPC_UART0->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
136 }
137 else if ((LPC_UART1_TypeDef *)LPC_UART == LPC_UART1)
138 {
139 LPC_PINCON->PINSEL4 &= ~0x0000000F;
140 LPC_PINCON->PINSEL4 |= 0x0000000A; /* Enable RxD1 P2.1, TxD1 P2.0 */
141
142 /* By default, the PCLKSELx value is zero, thus, the PCLK for
143 all the peripherals is 1/4 of the SystemFrequency. */
144 /* Bit 8,9 are for UART1 */
145 pclkdiv = (LPC_SC->PCLKSEL0 >> 8) & 0x03;
146 switch (pclkdiv)
147 {
148 case 0x00:
149 default:
150 pclk = SystemCoreClock / 4;
151 break;
152 case 0x01:
153 pclk = SystemCoreClock;
154 break;
155 case 0x02:
156 pclk = SystemCoreClock / 2;
157 break;
158 case 0x03:
159 pclk = SystemCoreClock / 8;
160 break;
161 }
162
163 LPC_UART1->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
164 Fdiv = (pclk / 16) / UART_BAUDRATE ; /*baud rate */
165 LPC_UART1->DLM = Fdiv / 256;
166 LPC_UART1->DLL = Fdiv % 256;
167 LPC_UART1->LCR = 0x03; /* DLAB = 0 */
168 LPC_UART1->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
169 }
170
171 /* Ensure a clean start, no data in either TX or RX FIFO. */
172 while ((LPC_UART->LSR & (LSR_THRE | LSR_TEMT)) != (LSR_THRE | LSR_TEMT));
173 while (LPC_UART->LSR & LSR_RDR)
174 {
175 Fdiv = LPC_UART->RBR; /* Dump data from RX FIFO */
176 }
177 LPC_UART->IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART interrupt */
178
179 return RT_EOK;
180 }
181
rt_uart_open(rt_device_t dev,rt_uint16_t oflag)182 static rt_err_t rt_uart_open(rt_device_t dev, rt_uint16_t oflag)
183 {
184 RT_ASSERT(dev != RT_NULL);
185 if (dev->flag & RT_DEVICE_FLAG_INT_RX)
186 {
187 /* Enable the UART Interrupt */
188 NVIC_EnableIRQ(UART_IRQn);
189 }
190
191 return RT_EOK;
192 }
193
rt_uart_close(rt_device_t dev)194 static rt_err_t rt_uart_close(rt_device_t dev)
195 {
196 RT_ASSERT(dev != RT_NULL);
197 if (dev->flag & RT_DEVICE_FLAG_INT_RX)
198 {
199 /* Disable the UART Interrupt */
200 NVIC_DisableIRQ(UART_IRQn);
201 }
202
203 return RT_EOK;
204 }
205
rt_uart_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)206 static rt_ssize_t rt_uart_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
207 {
208 rt_uint8_t *ptr;
209 struct rt_uart_lpc *uart = (struct rt_uart_lpc *)dev;
210 RT_ASSERT(uart != RT_NULL);
211
212 /* point to buffer */
213 ptr = (rt_uint8_t *) buffer;
214 if (dev->flag & RT_DEVICE_FLAG_INT_RX)
215 {
216 while (size)
217 {
218 /* interrupt receive */
219 rt_base_t level;
220
221 /* disable interrupt */
222 level = rt_hw_interrupt_disable();
223 if (uart->read_index != uart->save_index)
224 {
225 *ptr = uart->rx_buffer[uart->read_index];
226
227 uart->read_index ++;
228 if (uart->read_index >= RT_UART_RX_BUFFER_SIZE)
229 uart->read_index = 0;
230 }
231 else
232 {
233 /* no data in rx buffer */
234
235 /* enable interrupt */
236 rt_hw_interrupt_enable(level);
237 break;
238 }
239
240 /* enable interrupt */
241 rt_hw_interrupt_enable(level);
242
243 ptr ++;
244 size --;
245 }
246
247 return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
248 }
249
250 return 0;
251 }
252
rt_uart_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)253 static rt_ssize_t rt_uart_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
254 {
255 char *ptr;
256 ptr = (char *)buffer;
257
258 if (dev->flag & RT_DEVICE_FLAG_STREAM)
259 {
260 /* stream mode */
261 while (size)
262 {
263 if (*ptr == '\n')
264 {
265 /* THRE status, contain valid data */
266 while (!(LPC_UART->LSR & LSR_THRE));
267 /* write data */
268 LPC_UART->THR = '\r';
269 }
270
271 /* THRE status, contain valid data */
272 while (!(LPC_UART->LSR & LSR_THRE));
273 /* write data */
274 LPC_UART->THR = *ptr;
275
276 ptr ++;
277 size --;
278 }
279 }
280 else
281 {
282 while (size != 0)
283 {
284 /* THRE status, contain valid data */
285 while (!(LPC_UART->LSR & LSR_THRE));
286
287 /* write data */
288 LPC_UART->THR = *ptr;
289
290 ptr++;
291 size--;
292 }
293 }
294
295 return (rt_size_t) ptr - (rt_size_t) buffer;
296 }
297
rt_hw_uart_init(void)298 void rt_hw_uart_init(void)
299 {
300 struct rt_uart_lpc *uart;
301
302 /* get uart device */
303 uart = &uart_device;
304
305 /* device initialization */
306 uart->parent.type = RT_Device_Class_Char;
307 rt_memset(uart->rx_buffer, 0, sizeof(uart->rx_buffer));
308 uart->read_index = uart->save_index = 0;
309
310 /* device interface */
311 uart->parent.init = rt_uart_init;
312 uart->parent.open = rt_uart_open;
313 uart->parent.close = rt_uart_close;
314 uart->parent.read = rt_uart_read;
315 uart->parent.write = rt_uart_write;
316 uart->parent.control = RT_NULL;
317 uart->parent.user_data = RT_NULL;
318
319 rt_device_register(&uart->parent,
320 "uart0", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_INT_RX);
321 }
322 #endif /* end of UART */
323
324 /*@}*/
325