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