]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/AVR32_UC3/serial/serial.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / AVR32_UC3 / serial / serial.c
1 /*This file has been prepared for Doxygen automatic documentation generation.*/\r
2 /*! \file *********************************************************************\r
3  *\r
4  * \brief FreeRTOS Serial Port management example for AVR32 UC3.\r
5  *\r
6  * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32\r
7  * - Supported devices:  All AVR32 devices can be used.\r
8  * - AppNote:\r
9  *\r
10  * \author               Atmel Corporation: http://www.atmel.com \n\r
11  *                       Support and FAQ: http://support.atmel.no/\r
12  *\r
13  *****************************************************************************/\r
14 \r
15 /* Copyright (c) 2007, Atmel Corporation All rights reserved.\r
16  *\r
17  * Redistribution and use in source and binary forms, with or without\r
18  * modification, are permitted provided that the following conditions are met:\r
19  *\r
20  * 1. Redistributions of source code must retain the above copyright notice,\r
21  * this list of conditions and the following disclaimer.\r
22  *\r
23  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
24  * this list of conditions and the following disclaimer in the documentation\r
25  * and/or other materials provided with the distribution.\r
26  *\r
27  * 3. The name of ATMEL may not be used to endorse or promote products derived\r
28  * from this software without specific prior written permission.\r
29  *\r
30  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
31  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
32  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND\r
33  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,\r
34  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
35  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
36  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
37  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
38  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
39  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
40  */\r
41 \r
42 \r
43 /*\r
44   BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER FOR USART.\r
45 */\r
46 \r
47 /* Scheduler includes. */\r
48 #include "FreeRTOS.h"\r
49 #include "queue.h"\r
50 #include "task.h"\r
51 \r
52 /* Demo application includes. */\r
53 #include "serial.h"\r
54 #include <avr32/io.h>\r
55 #include "board.h"\r
56 #include "gpio.h"\r
57 \r
58 /*-----------------------------------------------------------*/\r
59 \r
60 /* Constants to setup and access the USART. */\r
61 #define serINVALID_COMPORT_HANDLER        ( ( xComPortHandle ) 0 )\r
62 #define serINVALID_QUEUE                  ( ( xQueueHandle ) 0 )\r
63 #define serHANDLE                         ( ( xComPortHandle ) 1 )\r
64 #define serNO_BLOCK                       ( ( portTickType ) 0 )\r
65 \r
66 /*-----------------------------------------------------------*/\r
67 \r
68 /* Queues used to hold received characters, and characters waiting to be\r
69 transmitted. */\r
70 static xQueueHandle xRxedChars;\r
71 static xQueueHandle xCharsForTx;\r
72 \r
73 /*-----------------------------------------------------------*/\r
74 \r
75 /* Forward declaration. */\r
76 static void vprvSerialCreateQueues( unsigned portBASE_TYPE uxQueueLength,\r
77                                                                         xQueueHandle *pxRxedChars,\r
78                                                                         xQueueHandle *pxCharsForTx );\r
79 \r
80 /*-----------------------------------------------------------*/\r
81 \r
82 #if __GNUC__\r
83         __attribute__((__noinline__))\r
84 #elif __ICCAVR32__\r
85         #pragma optimize = no_inline\r
86 #endif\r
87 \r
88 static portBASE_TYPE prvUSART_ISR_NonNakedBehaviour( void )\r
89 {\r
90         /* Now we can declare the local variables. */\r
91         signed portCHAR     cChar;\r
92         portBASE_TYPE     xHigherPriorityTaskWoken = pdFALSE;\r
93         unsigned portLONG     ulStatus;\r
94         volatile avr32_usart_t  *usart = serialPORT_USART;\r
95         portBASE_TYPE retstatus;\r
96 \r
97         /* What caused the interrupt? */\r
98         ulStatus = usart->csr & usart->imr;\r
99 \r
100         if (ulStatus & AVR32_USART_CSR_TXRDY_MASK)\r
101         {\r
102                 /* The interrupt was caused by the THR becoming empty.  Are there any\r
103                 more characters to transmit?\r
104                 Because FreeRTOS is not supposed to run with nested interrupts, put all OS\r
105                 calls in a critical section . */\r
106                 portENTER_CRITICAL();\r
107                         retstatus = xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken );\r
108                 portEXIT_CRITICAL();\r
109 \r
110                 if (retstatus == pdTRUE)\r
111                 {\r
112                         /* A character was retrieved from the queue so can be sent to the\r
113                          THR now. */\r
114                         usart->thr = cChar;\r
115                 }\r
116                 else\r
117                 {\r
118                         /* Queue empty, nothing to send so turn off the Tx interrupt. */\r
119                         usart->idr = AVR32_USART_IDR_TXRDY_MASK;\r
120                 }\r
121         }\r
122 \r
123         if (ulStatus & AVR32_USART_CSR_RXRDY_MASK)\r
124         {\r
125                 /* The interrupt was caused by the receiver getting data. */\r
126                 cChar = usart->rhr; //TODO\r
127 \r
128                 /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS\r
129                 calls in a critical section . */\r
130                 portENTER_CRITICAL();\r
131                         xQueueSendFromISR(xRxedChars, &cChar, &xHigherPriorityTaskWoken);\r
132                 portEXIT_CRITICAL();\r
133         }\r
134 \r
135         /* The return value will be used by portEXIT_SWITCHING_ISR() to know if it\r
136         should perform a vTaskSwitchContext(). */\r
137         return ( xHigherPriorityTaskWoken );\r
138 }\r
139 /*-----------------------------------------------------------*/\r
140 \r
141 /*\r
142  * USART interrupt service routine.\r
143  */\r
144 #if __GNUC__\r
145         __attribute__((__naked__))\r
146 #elif __ICCAVR32__\r
147         #pragma shadow_registers = full   // Naked.\r
148 #endif\r
149 \r
150 static void vUSART_ISR( void )\r
151 {\r
152         /* This ISR can cause a context switch, so the first statement must be a\r
153         call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any\r
154         variable declarations. */\r
155         portENTER_SWITCHING_ISR();\r
156 \r
157         prvUSART_ISR_NonNakedBehaviour();\r
158 \r
159         /* Exit the ISR.  If a task was woken by either a character being received\r
160         or transmitted then a context switch will occur. */\r
161         portEXIT_SWITCHING_ISR();\r
162 }\r
163 /*-----------------------------------------------------------*/\r
164 \r
165 \r
166 /*\r
167  * Init the serial port for the Minimal implementation.\r
168  */\r
169 xComPortHandle xSerialPortInitMinimal( unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )\r
170 {\r
171 static const gpio_map_t USART_GPIO_MAP =\r
172 {\r
173         { serialPORT_USART_RX_PIN, serialPORT_USART_RX_FUNCTION },\r
174         { serialPORT_USART_TX_PIN, serialPORT_USART_TX_FUNCTION }\r
175 };\r
176 \r
177 xComPortHandle    xReturn = serHANDLE;\r
178 volatile avr32_usart_t  *usart = serialPORT_USART;\r
179 int cd; /* USART Clock Divider. */\r
180 \r
181         /* Create the rx and tx queues. */\r
182         vprvSerialCreateQueues( uxQueueLength, &xRxedChars, &xCharsForTx );\r
183 \r
184         /* Configure USART. */\r
185         if( ( xRxedChars != serINVALID_QUEUE ) &&\r
186           ( xCharsForTx != serINVALID_QUEUE ) &&\r
187           ( ulWantedBaud != ( unsigned portLONG ) 0 ) )\r
188         {\r
189                 portENTER_CRITICAL();\r
190                 {\r
191                         /**\r
192                         ** Reset USART.\r
193                         **/\r
194                         /* Disable all USART interrupt sources to begin... */\r
195                         usart->idr = 0xFFFFFFFF;\r
196 \r
197                         /* Reset mode and other registers that could cause unpredictable\r
198                          behaviour after reset */\r
199                         usart->mr = 0; /* Reset Mode register. */\r
200                         usart->rtor = 0; /* Reset Receiver Time-out register. */\r
201                         usart->ttgr = 0; /* Reset Transmitter Timeguard register. */\r
202 \r
203                         /* Shutdown RX and TX, reset status bits, reset iterations in CSR, reset NACK\r
204                          and turn off DTR and RTS */\r
205                         usart->cr = AVR32_USART_CR_RSTRX_MASK   |\r
206                                            AVR32_USART_CR_RSTTX_MASK   |\r
207                                            AVR32_USART_CR_RXDIS_MASK   |\r
208                                            AVR32_USART_CR_TXDIS_MASK   |\r
209                                            AVR32_USART_CR_RSTSTA_MASK  |\r
210                                            AVR32_USART_CR_RSTIT_MASK   |\r
211                                            AVR32_USART_CR_RSTNACK_MASK |\r
212                                            AVR32_USART_CR_DTRDIS_MASK  |\r
213                                            AVR32_USART_CR_RTSDIS_MASK;\r
214 \r
215                         /**\r
216                         ** Configure USART.\r
217                         **/\r
218                         /* Enable USART RXD & TXD pins. */\r
219                         gpio_enable_module( USART_GPIO_MAP, sizeof( USART_GPIO_MAP ) / sizeof( USART_GPIO_MAP[0] ) );\r
220 \r
221                         /* Set the USART baudrate to be as close as possible to the wanted baudrate. */\r
222                         /*\r
223                         *             ** BAUDRATE CALCULATION **\r
224                         *\r
225                         *                 Selected Clock                       Selected Clock\r
226                         *     baudrate = ----------------   or     baudrate = ----------------\r
227                         *                    16 x CD                              8 x CD\r
228                         *\r
229                         *       (with 16x oversampling)              (with 8x oversampling)\r
230                         */\r
231 \r
232                         if( ulWantedBaud < ( configCPU_CLOCK_HZ / 16 ) )\r
233                         {\r
234                                 /* Use 8x oversampling */\r
235                                 usart->mr |= (1<<AVR32_USART_MR_OVER_OFFSET);\r
236                                 cd = configCPU_CLOCK_HZ / (8*ulWantedBaud);\r
237 \r
238                                 if( cd < 2 )\r
239                                 {\r
240                                         return serINVALID_COMPORT_HANDLER;\r
241                                 }\r
242 \r
243                                 usart->brgr = (cd << AVR32_USART_BRGR_CD_OFFSET);\r
244                         }\r
245                         else\r
246                         {\r
247                                 /* Use 16x oversampling */\r
248                                 usart->mr &= ~(1<<AVR32_USART_MR_OVER_OFFSET);\r
249                                 cd = configCPU_CLOCK_HZ / (16*ulWantedBaud);\r
250 \r
251                                 if( cd > 65535 )\r
252                                 {\r
253                                         /* Baudrate is too low */\r
254                                         return serINVALID_COMPORT_HANDLER;\r
255                                 }\r
256                         }\r
257 \r
258                         usart->brgr = (cd << AVR32_USART_BRGR_CD_OFFSET);\r
259 \r
260                         /* Set the USART Mode register: Mode=Normal(0), Clk selection=MCK(0),\r
261                         CHRL=8,  SYNC=0(asynchronous), PAR=None, NBSTOP=1, CHMODE=0, MSBF=0,\r
262                         MODE9=0, CKLO=0, OVER(previously done when setting the baudrate),\r
263                         other fields not used in this mode. */\r
264                         usart->mr |= ((8-5) << AVR32_USART_MR_CHRL_OFFSET  ) |\r
265                                         (   4  << AVR32_USART_MR_PAR_OFFSET   ) |\r
266                                         (   1  << AVR32_USART_MR_NBSTOP_OFFSET);\r
267 \r
268                         /* Write the Transmit Timeguard Register */\r
269                         usart->ttgr = 0;\r
270 \r
271 \r
272                         /* Register the USART interrupt handler to the interrupt controller and\r
273                          enable the USART interrupt. */\r
274                         INTC_register_interrupt((__int_handler)&vUSART_ISR, serialPORT_USART_IRQ, INT1);\r
275 \r
276                         /* Enable USART interrupt sources (but not Tx for now)... */\r
277                         usart->ier = AVR32_USART_IER_RXRDY_MASK;\r
278 \r
279                         /* Enable receiver and transmitter... */\r
280                         usart->cr |= AVR32_USART_CR_TXEN_MASK | AVR32_USART_CR_RXEN_MASK;\r
281                 }\r
282                 portEXIT_CRITICAL();\r
283         }\r
284         else\r
285         {\r
286                 xReturn = serINVALID_COMPORT_HANDLER;\r
287         }\r
288 \r
289         return xReturn;\r
290 }\r
291 /*-----------------------------------------------------------*/\r
292 \r
293 signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime )\r
294 {\r
295         /* The port handle is not required as this driver only supports UART0. */\r
296         ( void ) pxPort;\r
297 \r
298         /* Get the next character from the buffer.  Return false if no characters\r
299         are available, or arrive before xBlockTime expires. */\r
300         if( xQueueReceive( xRxedChars, pcRxedChar, xBlockTime ) )\r
301         {\r
302                 return pdTRUE;\r
303         }\r
304         else\r
305         {\r
306                 return pdFALSE;\r
307         }\r
308 }\r
309 /*-----------------------------------------------------------*/\r
310 \r
311 void vSerialPutString( xComPortHandle pxPort, const signed portCHAR * const pcString, unsigned portSHORT usStringLength )\r
312 {\r
313 signed portCHAR *pxNext;\r
314 \r
315         /* NOTE: This implementation does not handle the queue being full as no\r
316         block time is used! */\r
317 \r
318         /* The port handle is not required as this driver only supports UART0. */\r
319         ( void ) pxPort;\r
320 \r
321         /* Send each character in the string, one at a time. */\r
322         pxNext = ( signed portCHAR * ) pcString;\r
323         while( *pxNext )\r
324         {\r
325                 xSerialPutChar( pxPort, *pxNext, serNO_BLOCK );\r
326                 pxNext++;\r
327         }\r
328 }\r
329 /*-----------------------------------------------------------*/\r
330 \r
331 signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed portCHAR cOutChar, portTickType xBlockTime )\r
332 {\r
333 volatile avr32_usart_t  *usart = serialPORT_USART;\r
334 \r
335         /* Place the character in the queue of characters to be transmitted. */\r
336         if( xQueueSend( xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )\r
337         {\r
338                 return pdFAIL;\r
339         }\r
340 \r
341         /* Turn on the Tx interrupt so the ISR will remove the character from the\r
342         queue and send it.   This does not need to be in a critical section as\r
343         if the interrupt has already removed the character the next interrupt\r
344         will simply turn off the Tx interrupt again. */\r
345         usart->ier = (1 << AVR32_USART_IER_TXRDY_OFFSET);\r
346 \r
347         return pdPASS;\r
348 }\r
349 /*-----------------------------------------------------------*/\r
350 \r
351 void vSerialClose( xComPortHandle xPort )\r
352 {\r
353   /* Not supported as not required by the demo application. */\r
354 }\r
355 /*-----------------------------------------------------------*/\r
356 \r
357 /*###########################################################*/\r
358 \r
359 /*\r
360  * Create the rx and tx queues.\r
361  */\r
362 static void vprvSerialCreateQueues(  unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRxedChars, xQueueHandle *pxCharsForTx )\r
363 {\r
364         /* Create the queues used to hold Rx and Tx characters. */\r
365         xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );\r
366         xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );\r
367 \r
368         /* Pass back a reference to the queues so the serial API file can\r
369         post/receive characters. */\r
370         *pxRxedChars = xRxedChars;\r
371         *pxCharsForTx = xCharsForTx;\r
372 }\r
373 /*-----------------------------------------------------------*/\r