xref: /nrf52832-nimble/rt-thread/libcpu/arm/AT91SAM7S/serial.c (revision 104654410c56c573564690304ae786df310c91fc)
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