]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/lwIP_AVR32_UC3/SERIAL/serial.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / lwIP_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 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 USART0.\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 static portBASE_TYPE prvUSART0_ISR_NonNakedBehaviour( void )\r
88 {\r
89   /* Now we can declare the local variables. */\r
90   signed portCHAR     cChar;\r
91   portBASE_TYPE     xHigherPriorityTaskWoken = pdFALSE;\r
92   unsigned portLONG     ulStatus;\r
93   volatile avr32_usart_t  *usart0 = &AVR32_USART0;\r
94   portBASE_TYPE retstatus;\r
95 \r
96   /* What caused the interrupt? */\r
97   ulStatus = usart0->csr & usart0->imr;\r
98 \r
99   if (ulStatus & AVR32_USART_CSR_TXRDY_MASK)\r
100   {\r
101     /* The interrupt was caused by the THR becoming empty.  Are there any\r
102        more characters to transmit? */\r
103     /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS\r
104       calls in a critical section . */\r
105     portENTER_CRITICAL();\r
106     retstatus = xQueueReceiveFromISR(xCharsForTx, &cChar, &xHigherPriorityTaskWoken);\r
107     portEXIT_CRITICAL();\r
108     if (retstatus == pdTRUE)\r
109     {\r
110       /* A character was retrieved from the queue so can be sent to the\r
111          THR now. */\r
112       usart0->thr = cChar;\r
113     }\r
114     else\r
115     {\r
116       /* Queue empty, nothing to send so turn off the Tx interrupt. */\r
117       usart0->idr = AVR32_USART_IDR_TXRDY_MASK;\r
118     }\r
119   }\r
120 \r
121   if (ulStatus & AVR32_USART_CSR_RXRDY_MASK)\r
122   {\r
123     /* The interrupt was caused by the receiver getting data. */\r
124     cChar = usart0->rhr; //TODO\r
125 \r
126     /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS\r
127       calls in a critical section . */\r
128     portENTER_CRITICAL();\r
129         xQueueSendFromISR(xRxedChars, &cChar, &xHigherPriorityTaskWoken);\r
130     portEXIT_CRITICAL();\r
131   }\r
132 \r
133   /* The return value will be used by portEXIT_SWITCHING_ISR() to know if it\r
134   should perform a vTaskSwitchContext(). */\r
135   return ( xHigherPriorityTaskWoken );\r
136 }\r
137 \r
138 \r
139 /*\r
140  * USART0 interrupt service routine.\r
141  */\r
142 #if __GNUC__\r
143 __attribute__((__naked__))\r
144 #elif __ICCAVR32__\r
145 #pragma shadow_registers = full   // Naked.\r
146 #endif\r
147 static void vUSART0_ISR( void )\r
148 {\r
149 \r
150  /* This ISR can cause a context switch, so the first statement must be a\r
151   call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any\r
152   variable declarations. */\r
153   portENTER_SWITCHING_ISR();\r
154   prvUSART0_ISR_NonNakedBehaviour();\r
155  /* Exit the ISR.  If a task was woken by either a character being received\r
156   or transmitted then a context switch will occur. */\r
157   portEXIT_SWITCHING_ISR();\r
158 }\r
159 /*-----------------------------------------------------------*/\r
160 \r
161 \r
162 \r
163 /*\r
164  * Init the serial port for the Minimal implementation.\r
165  */\r
166 xComPortHandle xSerialPortInitMinimal( unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )\r
167 {\r
168   static const gpio_map_t USART0_GPIO_MAP =\r
169   {\r
170     { AVR32_USART0_RXD_0_PIN, AVR32_USART0_RXD_0_FUNCTION },\r
171     { AVR32_USART0_TXD_0_PIN, AVR32_USART0_TXD_0_FUNCTION }\r
172   };\r
173 \r
174   xComPortHandle    xReturn = serHANDLE;\r
175   volatile avr32_usart_t  *usart0 = &AVR32_USART0;\r
176   int                           cd; /* USART0 Clock Divider. */\r
177 \r
178   /* Create the rx and tx queues. */\r
179   vprvSerialCreateQueues( uxQueueLength, &xRxedChars, &xCharsForTx );\r
180 \r
181   /* Configure USART0. */\r
182   if( ( xRxedChars != serINVALID_QUEUE ) &&\r
183       ( xCharsForTx != serINVALID_QUEUE ) &&\r
184       ( ulWantedBaud != ( unsigned portLONG ) 0 ) )\r
185   {\r
186     portENTER_CRITICAL();\r
187     {\r
188       /**\r
189        ** Reset USART0.\r
190        **/\r
191       /* Disable all USART0 interrupt sources to begin... */\r
192       usart0->idr = 0xFFFFFFFF;\r
193 \r
194       /* Reset mode and other registers that could cause unpredictable\r
195          behaviour after reset */\r
196       usart0->mr = 0; /* Reset Mode register. */\r
197       usart0->rtor = 0; /* Reset Receiver Time-out register. */\r
198       usart0->ttgr = 0; /* Reset Transmitter Timeguard register. */\r
199 \r
200       /* Shutdown RX and TX, reset status bits, reset iterations in CSR, reset NACK\r
201          and turn off DTR and RTS */\r
202       usart0->cr = AVR32_USART_CR_RSTRX_MASK   |\r
203                    AVR32_USART_CR_RSTTX_MASK   |\r
204                    AVR32_USART_CR_RXDIS_MASK   |\r
205                    AVR32_USART_CR_TXDIS_MASK   |\r
206                    AVR32_USART_CR_RSTSTA_MASK  |\r
207                    AVR32_USART_CR_RSTIT_MASK   |\r
208                    AVR32_USART_CR_RSTNACK_MASK |\r
209                    AVR32_USART_CR_DTRDIS_MASK  |\r
210                    AVR32_USART_CR_RTSDIS_MASK;\r
211 \r
212       /**\r
213        ** Configure USART0.\r
214        **/\r
215       /* Enable USART0 RXD & TXD pins. */\r
216       gpio_enable_module( USART0_GPIO_MAP, sizeof( USART0_GPIO_MAP ) / sizeof( USART0_GPIO_MAP[0] ) );\r
217 \r
218       /* Set the USART0 baudrate to be as close as possible to the wanted baudrate. */\r
219       /*\r
220        *             ** BAUDRATE CALCULATION **\r
221        *\r
222        *                 Selected Clock                       Selected Clock\r
223        *     baudrate = ----------------   or     baudrate = ----------------\r
224        *                    16 x CD                              8 x CD\r
225        *\r
226        *       (with 16x oversampling)              (with 8x oversampling)\r
227        */\r
228       if ( ulWantedBaud < (configCPU_CLOCK_HZ/16)  ){\r
229         /* Use 8x oversampling */\r
230         usart0->mr |= (1<<AVR32_USART_MR_OVER_OFFSET);\r
231         cd = configCPU_CLOCK_HZ / (8*ulWantedBaud);\r
232 \r
233         if (cd < 2) {\r
234           return serINVALID_COMPORT_HANDLER;\r
235         }\r
236         usart0->brgr = (cd << AVR32_USART_BRGR_CD_OFFSET);\r
237       } else {\r
238         /* Use 16x oversampling */\r
239         usart0->mr &= ~(1<<AVR32_USART_MR_OVER_OFFSET);\r
240         cd =  configCPU_CLOCK_HZ / (16*ulWantedBaud);\r
241 \r
242         if (cd > 65535) {\r
243           /* Baudrate is too low */\r
244           return serINVALID_COMPORT_HANDLER;\r
245         }\r
246       }\r
247       usart0->brgr = (cd << AVR32_USART_BRGR_CD_OFFSET);\r
248 \r
249       /* Set the USART0 Mode register: Mode=Normal(0), Clk selection=MCK(0),\r
250          CHRL=8,  SYNC=0(asynchronous), PAR=None, NBSTOP=1, CHMODE=0, MSBF=0,\r
251          MODE9=0, CKLO=0, OVER(previously done when setting the baudrate),\r
252          other fields not used in this mode. */\r
253       usart0->mr |= ((8-5) << AVR32_USART_MR_CHRL_OFFSET  ) |\r
254                     (   4  << AVR32_USART_MR_PAR_OFFSET   ) |\r
255                     (   1  << AVR32_USART_MR_NBSTOP_OFFSET);\r
256 \r
257       /* Write the Transmit Timeguard Register */\r
258       usart0->ttgr = 0;\r
259 \r
260       // Register the USART0 interrupt handler to the interrupt controller and\r
261       // enable the USART0 interrupt.\r
262       INTC_register_interrupt((__int_handler)&vUSART0_ISR, AVR32_USART0_IRQ, INT1);\r
263 \r
264       /* Enable USART0 interrupt sources (but not Tx for now)... */\r
265       usart0->ier = AVR32_USART_IER_RXRDY_MASK;\r
266 \r
267       /* Enable receiver and transmitter... */\r
268       usart0->cr |= AVR32_USART_CR_TXEN_MASK | AVR32_USART_CR_RXEN_MASK;\r
269     }\r
270     portEXIT_CRITICAL();\r
271   }\r
272   else\r
273   {\r
274     xReturn = serINVALID_COMPORT_HANDLER;\r
275   }\r
276 \r
277   return xReturn;\r
278 }\r
279 /*-----------------------------------------------------------*/\r
280 \r
281 signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime )\r
282 {\r
283   /* The port handle is not required as this driver only supports UART0. */\r
284   ( void ) pxPort;\r
285 \r
286   /* Get the next character from the buffer.  Return false if no characters\r
287   are available, or arrive before xBlockTime expires. */\r
288   if( xQueueReceive( xRxedChars, pcRxedChar, xBlockTime ) )\r
289   {\r
290     return pdTRUE;\r
291   }\r
292   else\r
293   {\r
294     return pdFALSE;\r
295   }\r
296 }\r
297 /*-----------------------------------------------------------*/\r
298 \r
299 void vSerialPutString( xComPortHandle pxPort, const signed portCHAR * const pcString, unsigned portSHORT usStringLength )\r
300 {\r
301 signed portCHAR *pxNext;\r
302 \r
303   /* NOTE: This implementation does not handle the queue being full as no\r
304   block time is used! */\r
305 \r
306   /* The port handle is not required as this driver only supports UART0. */\r
307   ( void ) pxPort;\r
308 \r
309   /* Send each character in the string, one at a time. */\r
310   pxNext = ( signed portCHAR * ) pcString;\r
311   while( *pxNext )\r
312   {\r
313     xSerialPutChar( pxPort, *pxNext, serNO_BLOCK );\r
314     pxNext++;\r
315   }\r
316 }\r
317 /*-----------------------------------------------------------*/\r
318 \r
319 signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed portCHAR cOutChar, portTickType xBlockTime )\r
320 {\r
321 volatile avr32_usart_t  *usart0 = &AVR32_USART0;\r
322 \r
323   /* Place the character in the queue of characters to be transmitted. */\r
324   if( xQueueSend( xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )\r
325   {\r
326     return pdFAIL;\r
327   }\r
328 \r
329   /* Turn on the Tx interrupt so the ISR will remove the character from the\r
330   queue and send it.   This does not need to be in a critical section as\r
331   if the interrupt has already removed the character the next interrupt\r
332   will simply turn off the Tx interrupt again. */\r
333   usart0->ier = (1 << AVR32_USART_IER_TXRDY_OFFSET);\r
334 \r
335   return pdPASS;\r
336 }\r
337 /*-----------------------------------------------------------*/\r
338 \r
339 void vSerialClose( xComPortHandle xPort )\r
340 {\r
341   /* Not supported as not required by the demo application. */\r
342 }\r
343 /*-----------------------------------------------------------*/\r
344 \r
345 /*###########################################################*/\r
346 \r
347 /*\r
348  * Create the rx and tx queues.\r
349  */\r
350 static void vprvSerialCreateQueues(  unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRxedChars, xQueueHandle *pxCharsForTx )\r
351 {\r
352   /* Create the queues used to hold Rx and Tx characters. */\r
353   xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );\r
354   xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );\r
355 \r
356   /* Pass back a reference to the queues so the serial API file can\r
357   post/receive characters. */\r
358   *pxRxedChars = xRxedChars;\r
359   *pxCharsForTx = xCharsForTx;\r
360 }\r
361 /*-----------------------------------------------------------*/\r