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  * 2006-08-23     Bernard      first version
9  * 2009-05-14     Bernard      add RT-THread device interface
10  */
11 
12 #include <rthw.h>
13 #include <rtthread.h>
14 
15 #include "AT91SAM7S.h"
16 #include "serial.h"
17 
18 /**
19  * @addtogroup AT91SAM7
20  */
21 /*@{*/
22 typedef volatile rt_uint32_t REG32;
23 struct rt_at91serial_hw
24 {
25     REG32    US_CR;     // Control Register
26     REG32    US_MR;     // Mode Register
27     REG32    US_IER;    // Interrupt Enable Register
28     REG32    US_IDR;    // Interrupt Disable Register
29     REG32    US_IMR;    // Interrupt Mask Register
30     REG32    US_CSR;    // Channel Status Register
31     REG32    US_RHR;    // Receiver Holding Register
32     REG32    US_THR;    // Transmitter Holding Register
33     REG32    US_BRGR;   // Baud Rate Generator Register
34     REG32    US_RTOR;   // Receiver Time-out Register
35     REG32    US_TTGR;   // Transmitter Time-guard Register
36     REG32    Reserved0[5];  //
37     REG32    US_FIDI;   // FI_DI_Ratio Register
38     REG32    US_NER;    // Nb Errors Register
39     REG32    Reserved1[1];  //
40     REG32    US_IF;     // IRDA_FILTER Register
41     REG32    Reserved2[44];     //
42     REG32    US_RPR;    // Receive Pointer Register
43     REG32    US_RCR;    // Receive Counter Register
44     REG32    US_TPR;    // Transmit Pointer Register
45     REG32    US_TCR;    // Transmit Counter Register
46     REG32    US_RNPR;   // Receive Next Pointer Register
47     REG32    US_RNCR;   // Receive Next Counter Register
48     REG32    US_TNPR;   // Transmit Next Pointer Register
49     REG32    US_TNCR;   // Transmit Next Counter Register
50     REG32    US_PTCR;   // PDC Transfer Control Register
51     REG32    US_PTSR;   // PDC Transfer Status Register
52 };
53 
54 struct rt_at91serial
55 {
56     struct rt_device parent;
57 
58     struct rt_at91serial_hw* hw_base;
59     rt_uint16_t peripheral_id;
60     rt_uint32_t baudrate;
61 
62     /* reception field */
63     rt_uint16_t save_index, read_index;
64     rt_uint8_t  rx_buffer[RT_UART_RX_BUFFER_SIZE];
65 };
66 #ifdef RT_USING_UART1
67 struct rt_at91serial serial1;
68 #endif
69 #ifdef RT_USING_UART2
70 struct rt_at91serial serial2;
71 #endif
72 
rt_hw_serial_isr(int irqno)73 static void rt_hw_serial_isr(int irqno)
74 {
75     rt_base_t level;
76     struct rt_device* device;
77     struct rt_at91serial* serial = RT_NULL;
78 
79     if (irqno == AT91C_ID_US0)
80     {
81 #ifdef RT_USING_UART1
82         /* serial 1 */
83         serial = &serial1;
84 #endif
85     }
86     else if (irqno == AT91C_ID_US1)
87     {
88 #ifdef RT_USING_UART2
89         /* serial 2 */
90         serial = &serial2;
91 #endif
92     }
93     RT_ASSERT(serial != RT_NULL);
94 
95     /* get generic device object */
96     device = (rt_device_t)serial;
97 
98     /* disable interrupt */
99     level = rt_hw_interrupt_disable();
100 
101     /* get received character */
102     serial->rx_buffer[serial->save_index] = serial->hw_base->US_RHR;
103 
104     /* move to next position */
105     serial->save_index ++;
106     if (serial->save_index >= RT_UART_RX_BUFFER_SIZE)
107         serial->save_index = 0;
108 
109     /* if the next position is read index, discard this 'read char' */
110     if (serial->save_index == serial->read_index)
111     {
112         serial->read_index ++;
113         if (serial->read_index >= RT_UART_RX_BUFFER_SIZE)
114             serial->read_index = 0;
115     }
116 
117     /* enable interrupt */
118     rt_hw_interrupt_enable(level);
119 
120     /* indicate to upper layer application */
121     if (device->rx_indicate != RT_NULL)
122         device->rx_indicate(device, 1);
123 
124     /* ack interrupt */
125     AT91C_AIC_EOICR = 1;
126 }
127 
rt_serial_init(rt_device_t dev)128 static rt_err_t rt_serial_init (rt_device_t dev)
129 {
130     rt_uint32_t bd;
131     struct rt_at91serial* serial = (struct rt_at91serial*) dev;
132 
133     RT_ASSERT(serial != RT_NULL);
134     /* must be US0 or US1 */
135     RT_ASSERT(((serial->peripheral_id == AT91C_ID_US0) ||
136         (serial->peripheral_id == AT91C_ID_US1)));
137 
138     /* Enable Clock for USART */
139     AT91C_PMC_PCER = 1 << serial->peripheral_id;
140 
141     /* Enable RxD0 and TxDO Pin */
142     if (serial->peripheral_id == AT91C_ID_US0)
143     {
144         /* set pinmux */
145         AT91C_PIO_PDR = (1 << 5) | (1 << 6);
146     }
147     else if (serial->peripheral_id == AT91C_ID_US1)
148     {
149         /* set pinmux */
150         AT91C_PIO_PDR = (1 << 21) | (1 << 22);
151     }
152 
153     serial->hw_base->US_CR = AT91C_US_RSTRX |   /* Reset Receiver      */
154                     AT91C_US_RSTTX      |       /* Reset Transmitter   */
155                     AT91C_US_RXDIS      |       /* Receiver Disable    */
156                     AT91C_US_TXDIS;             /* Transmitter Disable */
157 
158     serial->hw_base->US_MR = AT91C_US_USMODE_NORMAL |   /* Normal Mode */
159                     AT91C_US_CLKS_CLOCK     |       /* Clock = MCK */
160                     AT91C_US_CHRL_8_BITS    |       /* 8-bit Data  */
161                     AT91C_US_PAR_NONE       |       /* No Parity   */
162                     AT91C_US_NBSTOP_1_BIT;          /* 1 Stop Bit  */
163 
164     /* set baud rate divisor */
165     bd =  ((MCK*10)/(serial->baudrate * 16));
166     if ((bd % 10) >= 5) bd = (bd / 10) + 1;
167     else bd /= 10;
168 
169     serial->hw_base->US_BRGR = bd;
170     serial->hw_base->US_CR = AT91C_US_RXEN |        /* Receiver Enable     */
171                     AT91C_US_TXEN;                  /* Transmitter Enable  */
172 
173     /* reset rx index */
174     serial->save_index = 0;
175     serial->read_index = 0;
176 
177     /* reset rx buffer */
178     rt_memset(serial->rx_buffer, 0, RT_UART_RX_BUFFER_SIZE);
179 
180     return RT_EOK;
181 }
182 
rt_serial_open(rt_device_t dev,rt_uint16_t oflag)183 static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag)
184 {
185     struct rt_at91serial *serial = (struct rt_at91serial*)dev;
186     RT_ASSERT(serial != RT_NULL);
187 
188     if (dev->flag & RT_DEVICE_FLAG_INT_RX)
189     {
190         /* enable UART rx interrupt */
191         serial->hw_base->US_IER = 1 << 0;       /* RxReady interrupt */
192         serial->hw_base->US_IMR |= 1 << 0;      /* umask RxReady interrupt */
193 
194         /* install UART handler */
195         rt_hw_interrupt_install(serial->peripheral_id, rt_hw_serial_isr, RT_NULL);
196         AT91C_AIC_SMR(serial->peripheral_id) = 5 | (0x01 << 5);
197         rt_hw_interrupt_umask(serial->peripheral_id);
198     }
199 
200     return RT_EOK;
201 }
202 
rt_serial_close(rt_device_t dev)203 static rt_err_t rt_serial_close(rt_device_t dev)
204 {
205     struct rt_at91serial *serial = (struct rt_at91serial*)dev;
206     RT_ASSERT(serial != RT_NULL);
207 
208     if (dev->flag & RT_DEVICE_FLAG_INT_RX)
209     {
210         /* disable interrupt */
211         serial->hw_base->US_IDR = 1 << 0;       /* RxReady interrupt */
212         serial->hw_base->US_IMR &= ~(1 << 0);   /* mask RxReady interrupt */
213     }
214 
215     return RT_EOK;
216 }
217 
rt_serial_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)218 static rt_ssize_t rt_serial_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
219 {
220     rt_uint8_t* ptr;
221     struct rt_at91serial *serial = (struct rt_at91serial*)dev;
222     RT_ASSERT(serial != RT_NULL);
223 
224     /* point to buffer */
225     ptr = (rt_uint8_t*) buffer;
226 
227     if (dev->flag & RT_DEVICE_FLAG_INT_RX)
228     {
229         while (size)
230         {
231             /* interrupt receive */
232             rt_base_t level;
233 
234             /* disable interrupt */
235             level = rt_hw_interrupt_disable();
236             if (serial->read_index != serial->save_index)
237             {
238                 *ptr = serial->rx_buffer[serial->read_index];
239 
240                 serial->read_index ++;
241                 if (serial->read_index >= RT_UART_RX_BUFFER_SIZE)
242                     serial->read_index = 0;
243             }
244             else
245             {
246                 /* no data in rx buffer */
247 
248                 /* enable interrupt */
249                 rt_hw_interrupt_enable(level);
250                 break;
251             }
252 
253             /* enable interrupt */
254             rt_hw_interrupt_enable(level);
255 
256             ptr ++; size --;
257         }
258 
259         return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
260     }
261     else if (dev->flag & RT_DEVICE_FLAG_DMA_RX)
262     {
263         /* not support right now */
264         RT_ASSERT(0);
265     }
266     else
267     {
268         /* poll mode */
269         while (size)
270         {
271             /* Wait for Full Rx Buffer */
272             while (!(serial->hw_base->US_CSR & AT91C_US_RXRDY));
273 
274             /* Read Character */
275             *ptr = serial->hw_base->US_RHR;
276             ptr ++;
277             size --;
278         }
279 
280         return (rt_size_t)ptr - (rt_size_t)buffer;
281     }
282 
283     return 0;
284 }
285 
rt_serial_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)286 static rt_ssize_t rt_serial_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
287 {
288     rt_uint8_t* ptr;
289     struct rt_at91serial *serial = (struct rt_at91serial*)dev;
290     RT_ASSERT(serial != RT_NULL);
291 
292     ptr = (rt_uint8_t*) buffer;
293     if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY)
294     {
295         if (dev->flag & RT_DEVICE_FLAG_STREAM)
296         {
297             /* it's a stream mode device */
298             while (size)
299             {
300                 /* stream mode */
301                 if (*ptr == '\n')
302                 {
303                     while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
304                     serial->hw_base->US_THR = '\r';
305                 }
306 
307                 /* Wait for Empty Tx Buffer */
308                 while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
309 
310                 /* Transmit Character */
311                 serial->hw_base->US_THR = *ptr;
312                 ptr ++; size --;
313             }
314         }
315         else
316         {
317             while (size)
318             {
319                 /* Wait for Empty Tx Buffer */
320                 while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
321 
322                 /* Transmit Character */
323                 serial->hw_base->US_THR = *ptr;
324                 ptr ++; size --;
325             }
326         }
327     }
328 
329     return (rt_size_t)ptr - (rt_size_t)buffer;
330 }
331 
rt_serial_control(rt_device_t dev,int cmd,void * args)332 static rt_err_t rt_serial_control (rt_device_t dev, int cmd, void *args)
333 {
334     return RT_EOK;
335 }
336 
rt_hw_serial_init()337 rt_err_t rt_hw_serial_init()
338 {
339     rt_device_t device;
340 
341 #ifdef RT_USING_UART1
342     device = (rt_device_t) &serial1;
343 
344     /* init serial device private data */
345     serial1.hw_base         = (struct rt_at91serial_hw*)AT91C_BASE_US0;
346     serial1.peripheral_id   = AT91C_ID_US0;
347     serial1.baudrate        = 115200;
348 
349     /* set device virtual interface */
350     device->init    = rt_serial_init;
351     device->open    = rt_serial_open;
352     device->close   = rt_serial_close;
353     device->read    = rt_serial_read;
354     device->write   = rt_serial_write;
355     device->control = rt_serial_control;
356 
357     /* register uart1 on device subsystem */
358     rt_device_register(device, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
359 #endif
360 
361 #ifdef RT_USING_UART2
362     device = (rt_device_t) &serial2;
363 
364     serial2.hw_base         = (struct rt_at91serial_hw*)AT91C_BASE_US1;
365     serial2.peripheral_id   = AT91C_ID_US1;
366     serial2.baudrate        = 115200;
367 
368     /* set device virtual interface */
369     device->init    = rt_serial_init;
370     device->open    = rt_serial_open;
371     device->close   = rt_serial_close;
372     device->read    = rt_serial_read;
373     device->write   = rt_serial_write;
374     device->control = rt_serial_control;
375 
376     /* register uart2 on device subsystem */
377     rt_device_register(device, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
378 #endif
379 
380     return RT_EOK;
381 }
382 
383 /*@}*/
384