summaryrefslogtreecommitdiff
path: root/Demo/lwIP_AVR32_UC3/SERIAL/serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'Demo/lwIP_AVR32_UC3/SERIAL/serial.c')
-rw-r--r--Demo/lwIP_AVR32_UC3/SERIAL/serial.c372
1 files changed, 372 insertions, 0 deletions
diff --git a/Demo/lwIP_AVR32_UC3/SERIAL/serial.c b/Demo/lwIP_AVR32_UC3/SERIAL/serial.c
new file mode 100644
index 000000000..b93bbf752
--- /dev/null
+++ b/Demo/lwIP_AVR32_UC3/SERIAL/serial.c
@@ -0,0 +1,372 @@
+/* This source file is part of the ATMEL FREERTOS-0.9.0 Release */
+
+/*This file has been prepared for Doxygen automatic documentation generation.*/
+/*! \file *********************************************************************
+ *
+ * \brief FreeRTOS serial port for AVR32 UC3.
+ *
+ * - Compiler: IAR EWAVR32 and GNU GCC for AVR32
+ * - Supported devices: All AVR32 devices can be used.
+ * - AppNote:
+ *
+ * \author Atmel Corporation: http://www.atmel.com \n
+ * Support email: avr32@atmel.com
+ *
+ *****************************************************************************/
+
+/* Copyright (c) 2007, Atmel Corporation All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of ATMEL may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
+ * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER FOR USART0.
+*/
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "task.h"
+
+/* Demo application includes. */
+#include "serial.h"
+#if __GNUC__
+# include <avr32/io.h>
+#elif __ICCAVR32__
+# include <avr32/iouc3a0512.h>
+#else
+# error Unknown compiler
+#endif
+#include "board.h"
+#include "gpio.h"
+
+/*-----------------------------------------------------------*/
+
+/* Constants to setup and access the USART. */
+#define serINVALID_COMPORT_HANDLER ( ( xComPortHandle ) 0 )
+#define serINVALID_QUEUE ( ( xQueueHandle ) 0 )
+#define serHANDLE ( ( xComPortHandle ) 1 )
+#define serNO_BLOCK ( ( portTickType ) 0 )
+
+/*-----------------------------------------------------------*/
+
+/* Queues used to hold received characters, and characters waiting to be
+transmitted. */
+static xQueueHandle xRxedChars;
+static xQueueHandle xCharsForTx;
+
+/*-----------------------------------------------------------*/
+
+/* Forward declaration. */
+static void vprvSerialCreateQueues( unsigned portBASE_TYPE uxQueueLength,
+ xQueueHandle *pxRxedChars,
+ xQueueHandle *pxCharsForTx );
+
+/*-----------------------------------------------------------*/
+
+#if __GNUC__
+__attribute__((__noinline__))
+#elif __ICCAVR32__
+#pragma optimize = no_inline
+#endif
+static portBASE_TYPE prvUSART0_ISR_NonNakedBehaviour( void )
+{
+ /* Now we can declare the local variables. */
+ signed portCHAR cChar;
+ portBASE_TYPE xTaskWokenByTx = pdFALSE, xTaskWokenByRx = pdFALSE;
+ unsigned portLONG ulStatus;
+ volatile avr32_usart_t *usart0 = &AVR32_USART0;
+ portBASE_TYPE retstatus;
+
+ /* What caused the interrupt? */
+ ulStatus = usart0->csr & usart0->imr;
+
+ if (ulStatus & AVR32_USART_CSR_TXRDY_MASK)
+ {
+ /* The interrupt was caused by the THR becoming empty. Are there any
+ more characters to transmit? */
+ /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS
+ calls in a critical section . */
+ portENTER_CRITICAL();
+ retstatus = xQueueReceiveFromISR(xCharsForTx, &cChar, &xTaskWokenByTx);
+ portEXIT_CRITICAL();
+ if (retstatus == pdTRUE)
+ {
+ /* A character was retrieved from the queue so can be sent to the
+ THR now. */
+ usart0->thr = cChar;
+ }
+ else
+ {
+ /* Queue empty, nothing to send so turn off the Tx interrupt. */
+ usart0->idr = AVR32_USART_IDR_TXRDY_MASK;
+ }
+ }
+
+ if (ulStatus & AVR32_USART_CSR_RXRDY_MASK)
+ {
+ /* The interrupt was caused by the receiver getting data. */
+ cChar = usart0->rhr; //TODO
+
+ /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS
+ calls in a critical section . */
+ portENTER_CRITICAL();
+ retstatus = xQueueSendFromISR(xRxedChars, &cChar, pdFALSE);
+ portEXIT_CRITICAL();
+ if (retstatus)
+ {
+ xTaskWokenByRx = pdTRUE;
+ }
+ }
+
+ /* The return value will be used by portEXIT_SWITCHING_ISR() to know if it
+ should perform a vTaskSwitchContext(). */
+ return ( xTaskWokenByTx || xTaskWokenByRx );
+}
+
+
+/*
+ * USART0 interrupt service routine.
+ */
+#if __GNUC__
+__attribute__((__naked__))
+#elif __ICCAVR32__
+#pragma shadow_registers = full // All registers shadowed
+#pragma handler = AVR32_USART0_IRQ_GROUP, 0
+__interrupt
+#endif
+static void vUSART0_ISR( void )
+{
+
+ /* This ISR can cause a context switch, so the first statement must be a
+ call to the portENTER_SWITCHING_ISR() macro. This must be BEFORE any
+ variable declarations. */
+ portENTER_SWITCHING_ISR();
+ prvUSART0_ISR_NonNakedBehaviour();
+ /* Exit the ISR. If a task was woken by either a character being received
+ or transmitted then a context switch will occur. */
+ portEXIT_SWITCHING_ISR();
+}
+/*-----------------------------------------------------------*/
+
+
+
+/*
+ * Init the serial port for the Minimal implementation.
+ */
+xComPortHandle xSerialPortInitMinimal( unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )
+{
+ xComPortHandle xReturn = serHANDLE;
+ volatile avr32_usart_t *usart0 = &AVR32_USART0;
+ int cd; /* USART0 Clock Divider. */
+
+ /* Create the rx and tx queues. */
+ vprvSerialCreateQueues( uxQueueLength, &xRxedChars, &xCharsForTx );
+
+ /* Configure USART0. */
+ if( ( xRxedChars != serINVALID_QUEUE ) &&
+ ( xCharsForTx != serINVALID_QUEUE ) &&
+ ( ulWantedBaud != ( unsigned portLONG ) 0 ) )
+ {
+ portENTER_CRITICAL();
+ {
+ /**
+ ** Reset USART0.
+ **/
+ /* Disable all USART0 interrupt sources to begin... */
+ usart0->idr = 0xFFFFFFFF;
+
+ /* Reset mode and other registers that could cause unpredictable
+ behaviour after reset */
+ usart0->mr = 0; /* Reset Mode register. */
+ usart0->rtor = 0; /* Reset Receiver Time-out register. */
+ usart0->ttgr = 0; /* Reset Transmitter Timeguard register. */
+
+ /* Shutdown RX and TX, reset status bits, reset iterations in CSR, reset NACK
+ and turn off DTR and RTS */
+ usart0->cr = AVR32_USART_CR_RSTRX_MASK |
+ AVR32_USART_CR_RSTTX_MASK |
+ AVR32_USART_CR_RXDIS_MASK |
+ AVR32_USART_CR_TXDIS_MASK |
+ AVR32_USART_CR_RSTSTA_MASK |
+ AVR32_USART_CR_RSTIT_MASK |
+ AVR32_USART_CR_RSTNACK_MASK |
+ AVR32_USART_CR_DTRDIS_MASK |
+ AVR32_USART_CR_RTSDIS_MASK;
+
+ /**
+ ** Configure USART0.
+ **/
+ /* Enable USART0 RXD & TXD pins. */
+ gpio_enable_module_pin(AVR32_USART0_RXD_0_PIN, AVR32_USART0_RXD_0_FUNCTION);
+ gpio_enable_module_pin(AVR32_USART0_TXD_0_PIN, AVR32_USART0_TXD_0_FUNCTION);
+
+ /* Set the USART0 baudrate to be as close as possible to the wanted baudrate. */
+ /*
+ * ** BAUDRATE CALCULATION **
+ *
+ * Selected Clock Selected Clock
+ * baudrate = ---------------- or baudrate = ----------------
+ * 16 x CD 8 x CD
+ *
+ * (with 16x oversampling) (with 8x oversampling)
+ */
+ if ( ulWantedBaud < (configCPU_CLOCK_HZ/16) ){
+ /* Use 8x oversampling */
+ usart0->mr |= (1<<AVR32_USART_MR_OVER_OFFSET);
+ cd = configCPU_CLOCK_HZ / (8*ulWantedBaud);
+
+ if (cd < 2) {
+ return serINVALID_COMPORT_HANDLER;
+ }
+ usart0->brgr = (cd << AVR32_USART_BRGR_CD_OFFSET);
+ } else {
+ /* Use 16x oversampling */
+ usart0->mr &= ~(1<<AVR32_USART_MR_OVER_OFFSET);
+ cd = configCPU_CLOCK_HZ / (16*ulWantedBaud);
+
+ if (cd > 65535) {
+ /* Baudrate is too low */
+ return serINVALID_COMPORT_HANDLER;
+ }
+ }
+ usart0->brgr = (cd << AVR32_USART_BRGR_CD_OFFSET);
+
+ /* Set the USART0 Mode register: Mode=Normal(0), Clk selection=MCK(0),
+ CHRL=8, SYNC=0(asynchronous), PAR=None, NBSTOP=1, CHMODE=0, MSBF=0,
+ MODE9=0, CKLO=0, OVER(previously done when setting the baudrate),
+ other fields not used in this mode. */
+ usart0->mr |= ((8-5) << AVR32_USART_MR_CHRL_OFFSET ) |
+ ( 4 << AVR32_USART_MR_PAR_OFFSET ) |
+ ( 1 << AVR32_USART_MR_NBSTOP_OFFSET);
+
+ /* Write the Transmit Timeguard Register */
+ usart0->ttgr = 0;
+
+#if __GNUC__
+ // Register the USART0 interrupt handler to the interrupt controller and
+ // enable the USART0 interrupt.
+ INTC_register_interrupt(&vUSART0_ISR, AVR32_USART0_IRQ, INT1);
+#endif
+
+ /* Enable USART0 interrupt sources (but not Tx for now)... */
+ usart0->ier = AVR32_USART_IER_RXRDY_MASK;
+
+ /* Enable receiver and transmitter... */
+ usart0->cr |= AVR32_USART_CR_TXEN_MASK | AVR32_USART_CR_RXEN_MASK;
+ }
+ portEXIT_CRITICAL();
+ }
+ else
+ {
+ xReturn = serINVALID_COMPORT_HANDLER;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime )
+{
+ /* The port handle is not required as this driver only supports UART0. */
+ ( void ) pxPort;
+
+ /* Get the next character from the buffer. Return false if no characters
+ are available, or arrive before xBlockTime expires. */
+ if( xQueueReceive( xRxedChars, pcRxedChar, xBlockTime ) )
+ {
+ return pdTRUE;
+ }
+ else
+ {
+ return pdFALSE;
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vSerialPutString( xComPortHandle pxPort, const signed portCHAR * const pcString, unsigned portSHORT usStringLength )
+{
+signed portCHAR *pxNext;
+
+ /* NOTE: This implementation does not handle the queue being full as no
+ block time is used! */
+
+ /* The port handle is not required as this driver only supports UART0. */
+ ( void ) pxPort;
+
+ /* Send each character in the string, one at a time. */
+ pxNext = ( signed portCHAR * ) pcString;
+ while( *pxNext )
+ {
+ xSerialPutChar( pxPort, *pxNext, serNO_BLOCK );
+ pxNext++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed portCHAR cOutChar, portTickType xBlockTime )
+{
+volatile avr32_usart_t *usart0 = &AVR32_USART0;
+
+ /* Place the character in the queue of characters to be transmitted. */
+ if( xQueueSend( xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
+ {
+ return pdFAIL;
+ }
+
+ /* Turn on the Tx interrupt so the ISR will remove the character from the
+ queue and send it. This does not need to be in a critical section as
+ if the interrupt has already removed the character the next interrupt
+ will simply turn off the Tx interrupt again. */
+ usart0->ier = (1 << AVR32_USART_IER_TXRDY_OFFSET);
+
+ return pdPASS;
+}
+/*-----------------------------------------------------------*/
+
+void vSerialClose( xComPortHandle xPort )
+{
+ /* Not supported as not required by the demo application. */
+}
+/*-----------------------------------------------------------*/
+
+/*###########################################################*/
+
+/*
+ * Create the rx and tx queues.
+ */
+static void vprvSerialCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRxedChars, xQueueHandle *pxCharsForTx )
+{
+ /* Create the queues used to hold Rx and Tx characters. */
+ xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );
+ xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );
+
+ /* Pass back a reference to the queues so the serial API file can
+ post/receive characters. */
+ *pxRxedChars = xRxedChars;
+ *pxCharsForTx = xCharsForTx;
+}
+/*-----------------------------------------------------------*/