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