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