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