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