1 /*This file has been prepared for Doxygen automatic documentation generation.*/
\r
2 /*! \file *********************************************************************
\r
4 * \brief FreeRTOS serial port for AVR32 UC3.
\r
6 * - Compiler: IAR EWAVR32 and GNU GCC for AVR32
\r
7 * - Supported devices: All AVR32 devices can be used.
\r
10 * \author Atmel Corporation: http://www.atmel.com \n
\r
11 * Support and FAQ: http://support.atmel.no/
\r
13 *****************************************************************************/
\r
15 /* Copyright (c) 2007, Atmel Corporation All rights reserved.
\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
20 * 1. Redistributions of source code must retain the above copyright notice,
\r
21 * this list of conditions and the following disclaimer.
\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
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
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
44 BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER FOR USART0.
\r
47 /* Scheduler includes. */
\r
48 #include "FreeRTOS.h"
\r
52 /* Demo application includes. */
\r
54 #include <avr32/io.h>
\r
58 /*-----------------------------------------------------------*/
\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
66 /*-----------------------------------------------------------*/
\r
68 /* Queues used to hold received characters, and characters waiting to be
\r
70 static xQueueHandle xRxedChars;
\r
71 static xQueueHandle xCharsForTx;
\r
73 /*-----------------------------------------------------------*/
\r
75 /* Forward declaration. */
\r
76 static void vprvSerialCreateQueues( unsigned portBASE_TYPE uxQueueLength,
\r
77 xQueueHandle *pxRxedChars,
\r
78 xQueueHandle *pxCharsForTx );
\r
80 /*-----------------------------------------------------------*/
\r
83 __attribute__((__noinline__))
\r
85 #pragma optimize = no_inline
\r
87 static portBASE_TYPE prvUSART0_ISR_NonNakedBehaviour( void )
\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
96 /* What caused the interrupt? */
\r
97 ulStatus = usart0->csr & usart0->imr;
\r
99 if (ulStatus & AVR32_USART_CSR_TXRDY_MASK)
\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
110 /* A character was retrieved from the queue so can be sent to the
\r
112 usart0->thr = cChar;
\r
116 /* Queue empty, nothing to send so turn off the Tx interrupt. */
\r
117 usart0->idr = AVR32_USART_IDR_TXRDY_MASK;
\r
121 if (ulStatus & AVR32_USART_CSR_RXRDY_MASK)
\r
123 /* The interrupt was caused by the receiver getting data. */
\r
124 cChar = usart0->rhr; //TODO
\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
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
140 * USART0 interrupt service routine.
\r
143 __attribute__((__naked__))
\r
145 #pragma shadow_registers = full // Naked.
\r
147 static void vUSART0_ISR( void )
\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
159 /*-----------------------------------------------------------*/
\r
164 * Init the serial port for the Minimal implementation.
\r
166 xComPortHandle xSerialPortInitMinimal( unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )
\r
168 static const gpio_map_t USART0_GPIO_MAP =
\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
174 xComPortHandle xReturn = serHANDLE;
\r
175 volatile avr32_usart_t *usart0 = &AVR32_USART0;
\r
176 int cd; /* USART0 Clock Divider. */
\r
178 /* Create the rx and tx queues. */
\r
179 vprvSerialCreateQueues( uxQueueLength, &xRxedChars, &xCharsForTx );
\r
181 /* Configure USART0. */
\r
182 if( ( xRxedChars != serINVALID_QUEUE ) &&
\r
183 ( xCharsForTx != serINVALID_QUEUE ) &&
\r
184 ( ulWantedBaud != ( unsigned portLONG ) 0 ) )
\r
186 portENTER_CRITICAL();
\r
191 /* Disable all USART0 interrupt sources to begin... */
\r
192 usart0->idr = 0xFFFFFFFF;
\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
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
213 ** Configure USART0.
\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
218 /* Set the USART0 baudrate to be as close as possible to the wanted baudrate. */
\r
220 * ** BAUDRATE CALCULATION **
\r
222 * Selected Clock Selected Clock
\r
223 * baudrate = ---------------- or baudrate = ----------------
\r
226 * (with 16x oversampling) (with 8x oversampling)
\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
234 return serINVALID_COMPORT_HANDLER;
\r
236 usart0->brgr = (cd << AVR32_USART_BRGR_CD_OFFSET);
\r
238 /* Use 16x oversampling */
\r
239 usart0->mr &= ~(1<<AVR32_USART_MR_OVER_OFFSET);
\r
240 cd = configCPU_CLOCK_HZ / (16*ulWantedBaud);
\r
243 /* Baudrate is too low */
\r
244 return serINVALID_COMPORT_HANDLER;
\r
247 usart0->brgr = (cd << AVR32_USART_BRGR_CD_OFFSET);
\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
257 /* Write the Transmit Timeguard Register */
\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
264 /* Enable USART0 interrupt sources (but not Tx for now)... */
\r
265 usart0->ier = AVR32_USART_IER_RXRDY_MASK;
\r
267 /* Enable receiver and transmitter... */
\r
268 usart0->cr |= AVR32_USART_CR_TXEN_MASK | AVR32_USART_CR_RXEN_MASK;
\r
270 portEXIT_CRITICAL();
\r
274 xReturn = serINVALID_COMPORT_HANDLER;
\r
279 /*-----------------------------------------------------------*/
\r
281 signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime )
\r
283 /* The port handle is not required as this driver only supports UART0. */
\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
297 /*-----------------------------------------------------------*/
\r
299 void vSerialPutString( xComPortHandle pxPort, const signed portCHAR * const pcString, unsigned portSHORT usStringLength )
\r
301 signed portCHAR *pxNext;
\r
303 /* NOTE: This implementation does not handle the queue being full as no
\r
304 block time is used! */
\r
306 /* The port handle is not required as this driver only supports UART0. */
\r
309 /* Send each character in the string, one at a time. */
\r
310 pxNext = ( signed portCHAR * ) pcString;
\r
313 xSerialPutChar( pxPort, *pxNext, serNO_BLOCK );
\r
317 /*-----------------------------------------------------------*/
\r
319 signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed portCHAR cOutChar, portTickType xBlockTime )
\r
321 volatile avr32_usart_t *usart0 = &AVR32_USART0;
\r
323 /* Place the character in the queue of characters to be transmitted. */
\r
324 if( xQueueSend( xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\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
337 /*-----------------------------------------------------------*/
\r
339 void vSerialClose( xComPortHandle xPort )
\r
341 /* Not supported as not required by the demo application. */
\r
343 /*-----------------------------------------------------------*/
\r
345 /*###########################################################*/
\r
348 * Create the rx and tx queues.
\r
350 static void vprvSerialCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRxedChars, xQueueHandle *pxCharsForTx )
\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
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
361 /*-----------------------------------------------------------*/
\r