]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/lwIP_AVR32_UC3/DRIVERS/USART/usart.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / lwIP_AVR32_UC3 / DRIVERS / USART / usart.c
1 /*This file is prepared for Doxygen automatic documentation generation.*/\r
2 /*! \file *********************************************************************\r
3  *\r
4  * \brief USART driver for AVR32 UC3.\r
5  *\r
6  * This file contains basic functions for the AVR32 USART, with support for all\r
7  * modes, settings and clock speeds.\r
8  *\r
9  * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32\r
10  * - Supported devices:  All AVR32 devices with a USART module can be used.\r
11  * - AppNote:\r
12  *\r
13  * \author               Atmel Corporation: http://www.atmel.com \n\r
14  *                       Support and FAQ: http://support.atmel.no/\r
15  *\r
16  ******************************************************************************/\r
17 \r
18 /* Copyright (c) 2007, Atmel Corporation All rights reserved.\r
19  *\r
20  * Redistribution and use in source and binary forms, with or without\r
21  * modification, are permitted provided that the following conditions are met:\r
22  *\r
23  * 1. Redistributions of source code must retain the above copyright notice,\r
24  * this list of conditions and the following disclaimer.\r
25  *\r
26  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
27  * this list of conditions and the following disclaimer in the documentation\r
28  * and/or other materials provided with the distribution.\r
29  *\r
30  * 3. The name of ATMEL may not be used to endorse or promote products derived\r
31  * from this software without specific prior written permission.\r
32  *\r
33  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
35  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND\r
36  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,\r
37  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
38  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
39  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
40  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
41  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
42  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
43  */\r
44 \r
45 \r
46 #include "usart.h"\r
47 \r
48 \r
49 //------------------------------------------------------------------------------\r
50 /*! \name Private Functions\r
51  */\r
52 //! @{\r
53 \r
54 \r
55 /*! \brief Checks if the USART is in multidrop mode.\r
56  *\r
57  * \param usart Base address of the USART instance.\r
58  *\r
59  * \return \c 1 if the USART is in multidrop mode, otherwise \c 0.\r
60  */\r
61 #if __GNUC__\r
62 __attribute__((__always_inline__))\r
63 #endif\r
64 static __inline__ int usart_mode_is_multidrop(volatile avr32_usart_t *usart)\r
65 {\r
66   return ((usart->mr >> AVR32_USART_MR_PAR_OFFSET) & AVR32_USART_MR_PAR_MULTI) == AVR32_USART_MR_PAR_MULTI;\r
67 }\r
68 \r
69 \r
70 /*! \brief Calculates a clock divider (\e CD) that gets the USART as close to a\r
71  *         wanted baudrate as possible.\r
72  *\r
73  * \todo manage the FP fractal part to avoid big errors\r
74  *\r
75  * Baudrate calculation:\r
76  * \f$ baudrate = \frac{Selected Clock}{16 \times CD} \f$ with 16x oversampling or\r
77  * \f$ baudrate = \frac{Selected Clock}{8 \times CD} \f$ with 8x oversampling or\r
78  * \f$ baudrate = \frac{Selected Clock}{CD} \f$ with SYNC bit set to allow high speed.\r
79  *\r
80  * \param usart     Base address of the USART instance.\r
81  * \param baudrate  Wanted baudrate.\r
82  * \param pba_hz    USART module input clock frequency (PBA clock, Hz).\r
83  *\r
84  * \retval USART_SUCCESS        Baudrate successfully initialized.\r
85  * \retval USART_INVALID_INPUT  Wanted baudrate is impossible with given clock speed.\r
86  */\r
87 \r
88 static int usart_set_baudrate(volatile avr32_usart_t *usart, unsigned int baudrate, long pba_hz)\r
89 {\r
90   // Clock divider.\r
91   int cd;\r
92 \r
93   // Baudrate calculation.\r
94   if (baudrate < pba_hz / 16)\r
95   {\r
96     // Use 16x oversampling, clear SYNC bit.\r
97     usart->mr &=~ (AVR32_USART_MR_OVER_MASK | AVR32_USART_MR_SYNC_MASK);\r
98     cd = (pba_hz + 8 * baudrate) / (16 * baudrate); \r
99 \r
100     if ((cd >65535)) return USART_INVALID_INPUT;\r
101   }\r
102   else if (baudrate < pba_hz / 8)\r
103   {\r
104     // Use 8x oversampling.\r
105     usart->mr |= AVR32_USART_MR_OVER_MASK;\r
106     // clear SYNC bit\r
107     usart->mr &=~ AVR32_USART_MR_SYNC_MASK;\r
108         \r
109     cd = (pba_hz + 4 * baudrate) / (8 * baudrate);\r
110 \r
111     if ((cd < 1)||(cd >65535)) return USART_INVALID_INPUT;\r
112   }\r
113   else\r
114   {\r
115     // set SYNC to 1 \r
116     usart->mr |= AVR32_USART_MR_SYNC_MASK;\r
117     // use PBA/BaudRate\r
118     cd = (pba_hz / baudrate);    \r
119   }\r
120   usart->brgr = cd << AVR32_USART_BRGR_CD_OFFSET;\r
121 \r
122   return USART_SUCCESS;\r
123 }\r
124 \r
125 //! @}\r
126 \r
127 \r
128 //------------------------------------------------------------------------------\r
129 /*! \name Initialization Functions\r
130  */\r
131 //! @{\r
132 \r
133 \r
134 void usart_reset(volatile avr32_usart_t *usart)\r
135 {\r
136   // Disable all USART interrupts.\r
137   // Interrupts needed should be set explicitly on every reset.\r
138   usart->idr = 0xFFFFFFFF;\r
139 \r
140   // Reset mode and other registers that could cause unpredictable behavior after reset.\r
141   usart->mr = 0;\r
142   usart->rtor = 0;\r
143   usart->ttgr = 0;\r
144 \r
145   // Shutdown TX and RX (will be re-enabled when setup has successfully completed),\r
146   // reset status bits and turn off DTR and RTS.\r
147   usart->cr = AVR32_USART_CR_RSTRX_MASK   |\r
148               AVR32_USART_CR_RSTTX_MASK   |\r
149               AVR32_USART_CR_RSTSTA_MASK  |\r
150               AVR32_USART_CR_RSTIT_MASK   |\r
151               AVR32_USART_CR_RSTNACK_MASK |\r
152               AVR32_USART_CR_DTRDIS_MASK  |\r
153               AVR32_USART_CR_RTSDIS_MASK;\r
154 }\r
155 \r
156 \r
157 int usart_init_rs232(volatile avr32_usart_t *usart, const usart_options_t *opt, long pba_hz)\r
158 {\r
159   // Reset the USART and shutdown TX and RX.\r
160   usart_reset(usart);\r
161 \r
162   // Check input values.\r
163   if (!opt) // Null pointer.\r
164     return USART_INVALID_INPUT;\r
165   if (opt->charlength < 5 || opt->charlength > 9 ||\r
166       opt->paritytype > 7 ||\r
167       opt->stopbits > 2 + 255 ||\r
168       opt->channelmode > 3)\r
169     return USART_INVALID_INPUT;\r
170 \r
171   if (usart_set_baudrate(usart, opt->baudrate, pba_hz) == USART_INVALID_INPUT)\r
172     return USART_INVALID_INPUT;\r
173 \r
174   if (opt->charlength == 9)\r
175   {\r
176     // Character length set to 9 bits. MODE9 dominates CHRL.\r
177     usart->mr |= AVR32_USART_MR_MODE9_MASK;\r
178   }\r
179   else\r
180   {\r
181     // CHRL gives the character length (- 5) when MODE9 = 0.\r
182     usart->mr |= (opt->charlength - 5) << AVR32_USART_MR_CHRL_OFFSET;\r
183   }\r
184 \r
185   usart->mr |= (opt->channelmode << AVR32_USART_MR_CHMODE_OFFSET) |\r
186                (opt->paritytype << AVR32_USART_MR_PAR_OFFSET);\r
187 \r
188   if (opt->stopbits > USART_2_STOPBITS)\r
189   {\r
190     // Set two stop bits\r
191     usart->mr |= AVR32_USART_MR_NBSTOP_2 << AVR32_USART_MR_NBSTOP_OFFSET;\r
192     // and a timeguard period gives the rest.\r
193     usart->ttgr = opt->stopbits - USART_2_STOPBITS;\r
194   }\r
195   else\r
196     // Insert 1, 1.5 or 2 stop bits.\r
197     usart->mr |= opt->stopbits << AVR32_USART_MR_NBSTOP_OFFSET;\r
198 \r
199   // Setup complete; enable communication.\r
200   // Enable input and output.\r
201   usart->cr |= AVR32_USART_CR_TXEN_MASK |\r
202                AVR32_USART_CR_RXEN_MASK;\r
203 \r
204   return USART_SUCCESS;\r
205 }\r
206 \r
207 \r
208 int usart_init_hw_handshaking(volatile avr32_usart_t *usart, const usart_options_t *opt, long pba_hz)\r
209 {\r
210   // First: Setup standard RS232.\r
211   if (usart_init_rs232(usart, opt, pba_hz) == USART_INVALID_INPUT)\r
212     return USART_INVALID_INPUT;\r
213 \r
214   // Clear previous mode.\r
215   usart->mr &= ~AVR32_USART_MR_MODE_MASK;\r
216   // Hardware handshaking.\r
217   usart->mr |= USART_MODE_HW_HSH << AVR32_USART_MR_MODE_OFFSET;\r
218 \r
219   return USART_SUCCESS;\r
220 }\r
221 \r
222 \r
223 int usart_init_IrDA(volatile avr32_usart_t *usart, const usart_options_t *opt,\r
224                     long pba_hz, unsigned char irda_filter)\r
225 {\r
226   // First: Setup standard RS232.\r
227   if (usart_init_rs232(usart, opt, pba_hz) == USART_INVALID_INPUT)\r
228     return USART_INVALID_INPUT;\r
229 \r
230   // Set IrDA counter.\r
231   usart->ifr = irda_filter;\r
232 \r
233   // Activate "low-pass filtering" of input.\r
234   usart->mr |= AVR32_USART_MR_FILTER_MASK;\r
235 \r
236   return USART_SUCCESS;\r
237 }\r
238 \r
239 \r
240 int usart_init_modem(volatile avr32_usart_t *usart, const usart_options_t *opt, long pba_hz)\r
241 {\r
242   // First: Setup standard RS232.\r
243   if (usart_init_rs232(usart, opt, pba_hz) == USART_INVALID_INPUT)\r
244     return USART_INVALID_INPUT;\r
245 \r
246   // Clear previous mode.\r
247   usart->mr &= ~AVR32_USART_MR_MODE_MASK;\r
248   // Set modem mode.\r
249   usart->mr |= USART_MODE_MODEM << AVR32_USART_MR_MODE_OFFSET;\r
250 \r
251   return USART_SUCCESS;\r
252 }\r
253 \r
254 \r
255 int usart_init_rs485(volatile avr32_usart_t *usart, const usart_options_t *opt, long pba_hz)\r
256 {\r
257   // First: Setup standard RS232.\r
258   if (usart_init_rs232(usart, opt, pba_hz) == USART_INVALID_INPUT)\r
259     return USART_INVALID_INPUT;\r
260 \r
261   // Clear previous mode.\r
262   usart->mr &= ~AVR32_USART_MR_MODE_MASK;\r
263   // Set RS485 mode.\r
264   usart->mr |= USART_MODE_RS485 << AVR32_USART_MR_MODE_OFFSET;\r
265 \r
266   return USART_SUCCESS;\r
267 }\r
268 \r
269 \r
270 int usart_init_iso7816(volatile avr32_usart_t *usart, const iso7816_options_t *opt, int t, long pba_hz)\r
271 {\r
272   // Reset the USART and shutdown TX and RX.\r
273   usart_reset(usart);\r
274 \r
275   // Check input values.\r
276   if (!opt) // Null pointer.\r
277     return USART_INVALID_INPUT;\r
278 \r
279   if (t == 0)\r
280   {\r
281     // Set USART mode to ISO7816, T=0.\r
282     // The T=0 protocol always uses 2 stop bits.\r
283     usart->mr = (USART_MODE_ISO7816_T0 << AVR32_USART_MR_MODE_OFFSET) |\r
284                 (AVR32_USART_MR_NBSTOP_2 << AVR32_USART_MR_NBSTOP_OFFSET) |\r
285                 (opt->bit_order << AVR32_USART_MR_MSBF_OFFSET); // Allow MSBF in T=0.\r
286   }\r
287   else if (t == 1)\r
288   {\r
289     // Only LSB first in the T=1 protocol.\r
290     // max_iterations field is only used in T=0 mode.\r
291     if (opt->bit_order != 0 ||\r
292         opt->max_iterations != 0)\r
293       return USART_INVALID_INPUT;\r
294     // Set USART mode to ISO7816, T=1.\r
295     // The T=1 protocol always uses 1 stop bit.\r
296     usart->mr = (USART_MODE_ISO7816_T1 << AVR32_USART_MR_MODE_OFFSET) |\r
297                 (AVR32_USART_MR_NBSTOP_1 << AVR32_USART_MR_NBSTOP_OFFSET);\r
298   }\r
299   else\r
300     return USART_INVALID_INPUT;\r
301 \r
302   if (usart_set_baudrate(usart, opt->iso7816_hz, pba_hz) == USART_INVALID_INPUT)\r
303     return USART_INVALID_INPUT;\r
304 \r
305   // Set FIDI register: bit rate = selected clock/FI_DI_ratio/16.\r
306   usart->fidi = opt->fidi_ratio;\r
307   // Set ISO7816 spesific options in the MODE register.\r
308   usart->mr |= (opt->inhibit_nack << AVR32_USART_MR_INACK_OFFSET) |\r
309                (opt->dis_suc_nack << AVR32_USART_MR_DSNACK_OFFSET) |\r
310                (opt->max_iterations << AVR32_USART_MR_MAX_ITERATION_OFFSET) |\r
311                AVR32_USART_MR_CLKO_MASK;  // Enable clock output.\r
312 \r
313   // Setup complete; enable input.\r
314   // Leave TX disabled for now.\r
315   usart->cr |= AVR32_USART_CR_RXEN_MASK;\r
316 \r
317   return USART_SUCCESS;\r
318 }\r
319 //! @}\r
320 \r
321 \r
322 //------------------------------------------------------------------------------\r
323 /*! \name Transmit/Receive Functions\r
324  */\r
325 //! @{\r
326 \r
327 \r
328 int usart_send_address(volatile avr32_usart_t *usart, int address)\r
329 {\r
330   // Check if USART is in multidrop / RS485 mode.\r
331   if (!usart_mode_is_multidrop(usart)) return USART_MODE_FAULT;\r
332 \r
333   // Prepare to send an address.\r
334   usart->cr |= AVR32_USART_CR_SENDA_MASK;\r
335 \r
336   // Write the address to TX.\r
337   usart_bw_write_char(usart, address);\r
338 \r
339   return USART_SUCCESS;\r
340 }\r
341 \r
342 \r
343 int usart_write_char(volatile avr32_usart_t *usart, int c)\r
344 {\r
345   if (usart->csr & AVR32_USART_CSR_TXRDY_MASK)\r
346   {\r
347     usart->thr = c;\r
348     return USART_SUCCESS;\r
349   }\r
350   else\r
351     return USART_TX_BUSY;\r
352 }\r
353 \r
354 \r
355 int usart_putchar(volatile avr32_usart_t *usart, int c)\r
356 {\r
357   int timeout = USART_DEFAULT_TIMEOUT;\r
358 \r
359   if (c == '\n')\r
360   {\r
361     do\r
362     {\r
363       if (!timeout--) return USART_FAILURE;\r
364     } while (usart_write_char(usart, '\r') != USART_SUCCESS);\r
365 \r
366     timeout = USART_DEFAULT_TIMEOUT;\r
367   }\r
368 \r
369   do\r
370   {\r
371     if (!timeout--) return USART_FAILURE;\r
372   } while (usart_write_char(usart, c) != USART_SUCCESS);\r
373 \r
374   return USART_SUCCESS;\r
375 }\r
376 \r
377 \r
378 int usart_read_char(volatile avr32_usart_t *usart, int *c)\r
379 {\r
380   // Check for errors: frame, parity and overrun. In RS485 mode, a parity error\r
381   // would mean that an address char has been received.\r
382   if (usart->csr & (AVR32_USART_CSR_OVRE_MASK |\r
383                     AVR32_USART_CSR_FRAME_MASK |\r
384                     AVR32_USART_CSR_PARE_MASK))\r
385     return USART_RX_ERROR;\r
386 \r
387   // No error; if we really did receive a char, read it and return SUCCESS.\r
388   if (usart->csr & AVR32_USART_CSR_RXRDY_MASK)\r
389   {\r
390     *c = (unsigned short)usart->rhr;\r
391     return USART_SUCCESS;\r
392   }\r
393   else\r
394     return USART_RX_EMPTY;\r
395 }\r
396 \r
397 \r
398 int usart_getchar(volatile avr32_usart_t *usart)\r
399 {\r
400   int c, ret;\r
401 \r
402   while ((ret = usart_read_char(usart, &c)) == USART_RX_EMPTY);\r
403 \r
404   if (ret == USART_RX_ERROR)\r
405     return USART_FAILURE;\r
406 \r
407   return c;\r
408 }\r
409 \r
410 \r
411 void usart_write_line(volatile avr32_usart_t *usart, const char *string)\r
412 {\r
413   while (*string != '\0')\r
414     usart_putchar(usart, *string++);\r
415 }\r
416 \r
417 \r
418 int usart_get_echo_line(volatile avr32_usart_t *usart)\r
419 {\r
420   int rx_char;\r
421   int retval = USART_SUCCESS;\r
422 \r
423   while (1)\r
424   {\r
425     rx_char = usart_getchar(usart);\r
426     if (rx_char == USART_FAILURE)\r
427     {\r
428       usart_write_line(usart, "Error!!!\n");\r
429       break;\r
430     }\r
431     if (rx_char == '\x03')\r
432     {\r
433       retval = USART_FAILURE;\r
434       break;\r
435     }\r
436     usart_putchar(usart, rx_char);\r
437     if (rx_char == '\r')\r
438     {\r
439       usart_putchar(usart, '\n');\r
440       break;\r
441     }\r
442   }\r
443 \r
444   return retval;\r
445 }\r
446 \r
447 \r
448 //! @}\r