1 /*
2 * Copyright (c) 2006-2018, 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_size_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_size_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