uart1.c

00001 /*
00002  * Copyright (c) 2006, Swedish Institute of Computer Science
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * @(#)$Id: uart1.c,v 1.24 2011/01/19 20:44:20 joxe Exp $
00030  */
00031 
00032 /*
00033  * Machine dependent MSP430 UART1 code.
00034  */
00035 
00036 #include <stdlib.h>
00037 #include <io.h>
00038 #include <signal.h>
00039 
00040 #include <stdio.h>
00041 
00042 #include "sys/energest.h"
00043 #include "dev/uart1.h"
00044 #include "dev/watchdog.h"
00045 #include "sys/ctimer.h"
00046 #include "lib/ringbuf.h"
00047 
00048 static int (*uart1_input_handler)(unsigned char c);
00049 static volatile uint8_t rx_in_progress;
00050 
00051 static volatile uint8_t transmitting;
00052 
00053 #ifdef UART1_CONF_TX_WITH_INTERRUPT
00054 #define TX_WITH_INTERRUPT UART1_CONF_TX_WITH_INTERRUPT
00055 #else /* UART1_CONF_TX_WITH_INTERRUPT */
00056 #define TX_WITH_INTERRUPT 0
00057 #endif /* UART1_CONF_TX_WITH_INTERRUPT */
00058 
00059 #ifdef UART1_CONF_RX_WITH_DMA
00060 #define RX_WITH_DMA UART1_CONF_RX_WITH_DMA
00061 #else /* UART1_CONF_RX_WITH_DMA */
00062 #define RX_WITH_DMA 0
00063 #endif /* UART1_CONF_RX_WITH_DMA */
00064 
00065 #if RX_WITH_DMA
00066 #warning RX_WITH_DMA ENABLED - WILL NOT WORK WITH MSPSIM / COOJA!
00067 #endif /* RX_WITH_DMA */
00068 
00069 #if TX_WITH_INTERRUPT
00070 #define TXBUFSIZE 128
00071 
00072 static struct ringbuf txbuf;
00073 static uint8_t txbuf_data[TXBUFSIZE];
00074 #endif /* TX_WITH_INTERRUPT */
00075 
00076 #if RX_WITH_DMA
00077 #define RXBUFSIZE 128
00078 
00079 static uint8_t rxbuf[RXBUFSIZE];
00080 static uint16_t last_size;
00081 static struct ctimer rxdma_timer;
00082 
00083 static void
00084 handle_rxdma_timer(void *ptr)
00085 {
00086   uint16_t size;
00087   size = DMA0SZ; /* Note: loop requires that size is less or eq to RXBUFSIZE */
00088   while(last_size != size) {
00089 /*     printf("read: %c [%d,%d]\n", (unsigned char)rxbuf[RXBUFSIZE - last_size], */
00090 /*         last_size, size); */
00091     uart1_input_handler((unsigned char)rxbuf[RXBUFSIZE - last_size]);
00092     last_size--;
00093     if(last_size == 0) last_size = RXBUFSIZE;
00094   }
00095 
00096   ctimer_reset(&rxdma_timer);
00097 }
00098 #endif /* RX_WITH_DMA */
00099 
00100 /*---------------------------------------------------------------------------*/
00101 uint8_t
00102 uart1_active(void)
00103 {
00104   return ((~ UTCTL1) & TXEPT) | rx_in_progress | transmitting;
00105 }
00106 /*---------------------------------------------------------------------------*/
00107 void
00108 uart1_set_input(int (*input)(unsigned char c))
00109 {
00110 #if RX_WITH_DMA /* This needs to be called after ctimer process is started */
00111   ctimer_set(&rxdma_timer, CLOCK_SECOND/64, handle_rxdma_timer, NULL);
00112 #endif
00113   uart1_input_handler = input;
00114 }
00115 /*---------------------------------------------------------------------------*/
00116 void
00117 uart1_writeb(unsigned char c)
00118 {
00119   watchdog_periodic();
00120 #if TX_WITH_INTERRUPT
00121 
00122   /* Put the outgoing byte on the transmission buffer. If the buffer
00123      is full, we just keep on trying to put the byte into the buffer
00124      until it is possible to put it there. */
00125   while(ringbuf_put(&txbuf, c) == 0);
00126 
00127   /* If there is no transmission going, we need to start it by putting
00128      the first byte into the UART. */
00129   if(transmitting == 0) {
00130     transmitting = 1;
00131 
00132     /* Loop until the transmission buffer is available. */
00133     /*while((IFG2 & UTXIFG1) == 0);*/
00134     TXBUF1 = ringbuf_get(&txbuf);
00135   }
00136 
00137 #else /* TX_WITH_INTERRUPT */
00138 
00139   /* Loop until the transmission buffer is available. */
00140   while((IFG2 & UTXIFG1) == 0);
00141 
00142   /* Transmit the data. */
00143   TXBUF1 = c;
00144 #endif /* TX_WITH_INTERRUPT */
00145 }
00146 /*---------------------------------------------------------------------------*/
00147 /**
00148  * Initalize the RS232 port.
00149  *
00150  */
00151 void
00152 uart1_init(unsigned long ubr)
00153 {
00154   /* RS232 */
00155   P3DIR &= ~0x80;                       /* Select P37 for input (UART1RX) */
00156   P3DIR |= 0x40;                        /* Select P36 for output (UART1TX) */
00157   P3SEL |= 0xC0;                        /* Select P36,P37 for UART1{TX,RX} */
00158 
00159   UCTL1 = SWRST | CHAR;                 /* 8-bit character, UART mode */
00160 
00161 #if 0
00162    U1RCTL &= ~URXEIE; /* even erroneous characters trigger interrupts */
00163 #endif
00164 
00165   UTCTL1 = SSEL1;                       /* UCLK = MCLK */
00166 
00167   UBR01 = ubr;
00168   UBR11 = ubr >> 8;
00169   /*
00170    * UMCTL1 values calculated using
00171    * http://mspgcc.sourceforge.net/baudrate.html
00172    */
00173   switch(ubr) {
00174 
00175 #if F_CPU == 3900000ul
00176 
00177   case UART1_BAUD2UBR(115200ul):
00178     UMCTL1 = 0xF7;
00179     break;
00180   case UART1_BAUD2UBR(57600ul):
00181     UMCTL1 = 0xED;
00182     break;
00183   case UART1_BAUD2UBR(38400ul):
00184     UMCTL1 = 0xD6;
00185     break;
00186   case UART1_BAUD2UBR(19200ul):
00187     UMCTL1 = 0x08;
00188     break;
00189   case UART1_BAUD2UBR(9600ul):
00190     UMCTL1 = 0x22;
00191     break;
00192 
00193 #elif F_CPU == 2457600ul
00194 
00195   case UART1_BAUD2UBR(115200ul):
00196     UMCTL1 = 0x4A;
00197     break;
00198   case UART1_BAUD2UBR(57600ul):
00199     UMCTL1 = 0x5B;
00200     break;
00201   default:
00202     /* 9600, 19200, 38400 don't require any correction */
00203     UMCTL1 = 0x00;
00204 
00205 #else
00206 
00207 #error Unsupported CPU speed in uart1.c
00208 
00209 #endif
00210   }
00211 
00212   ME2 &= ~USPIE1;                       /* USART1 SPI module disable */
00213   ME2 |= (UTXE1 | URXE1);               /* Enable USART1 TXD/RXD */
00214 
00215   UCTL1 &= ~SWRST;
00216 
00217   /* XXX Clear pending interrupts before enable!!! */
00218   IFG2 &= ~URXIFG1;
00219   U1TCTL |= URXSE;
00220 
00221   rx_in_progress = 0;
00222 
00223   transmitting = 0;
00224 
00225   IE2 |= URXIE1;                        /* Enable USART1 RX interrupt  */
00226 #if TX_WITH_INTERRUPT
00227   ringbuf_init(&txbuf, txbuf_data, sizeof(txbuf_data));
00228   IE2 |= UTXIE1;                        /* Enable USART1 TX interrupt  */
00229 #endif /* TX_WITH_INTERRUPT */
00230 
00231 #if RX_WITH_DMA
00232   IE2 &= ~URXIE1; /* disable USART1 RX interrupt  */
00233   /* UART1_RX trigger */
00234   DMACTL0 = DMA0TSEL_9;
00235 
00236   /* source address = RXBUF1 */
00237   DMA0SA = (unsigned int) &RXBUF1;
00238   DMA0DA = (unsigned int) &rxbuf;
00239   DMA0SZ = RXBUFSIZE;
00240   last_size = RXBUFSIZE;
00241   DMA0CTL = DMADT_4 + DMASBDB + DMADSTINCR_3 + DMAEN + DMAREQ;// DMAIE;
00242 
00243   msp430_add_lpm_req(MSP430_REQUIRE_LPM1);
00244 #endif /* RX_WITH_DMA */
00245 
00246 }
00247 
00248 
00249 /*---------------------------------------------------------------------------*/
00250 #if !RX_WITH_DMA
00251 interrupt(UART1RX_VECTOR)
00252 uart1_rx_interrupt(void)
00253 {
00254   uint8_t c;
00255   ENERGEST_ON(ENERGEST_TYPE_IRQ);
00256 
00257   if(!(URXIFG1 & IFG2)) {
00258     /* Edge detect if IFG not set? */
00259     U1TCTL &= ~URXSE; /* Clear the URXS signal */
00260     U1TCTL |= URXSE;  /* Re-enable URXS - needed here?*/
00261     rx_in_progress = 1;
00262     LPM4_EXIT;
00263   } else {
00264     rx_in_progress = 0;
00265     /* Check status register for receive errors. */
00266     if(URCTL1 & RXERR) {
00267       c = RXBUF1;   /* Clear error flags by forcing a dummy read. */
00268     } else {
00269       c = RXBUF1;
00270       if(uart1_input_handler != NULL) {
00271         if(uart1_input_handler(c)) {
00272           LPM4_EXIT;
00273         }
00274       }
00275     }
00276   }
00277 
00278   ENERGEST_OFF(ENERGEST_TYPE_IRQ);
00279 }
00280 #endif /* !RX_WITH_DMA */
00281 /*---------------------------------------------------------------------------*/
00282 #if TX_WITH_INTERRUPT
00283 interrupt(UART1TX_VECTOR)
00284 uart1_tx_interrupt(void)
00285 {
00286   ENERGEST_ON(ENERGEST_TYPE_IRQ);
00287 
00288   if(ringbuf_elements(&txbuf) == 0) {
00289     transmitting = 0;
00290   } else {
00291     TXBUF1 = ringbuf_get(&txbuf);
00292   }
00293 
00294   ENERGEST_OFF(ENERGEST_TYPE_IRQ);
00295 }
00296 #endif /* TX_WITH_INTERRUPT */
00297 /*---------------------------------------------------------------------------*/

Generated on Mon Apr 11 14:23:38 2011 for Contiki 2.5 by  doxygen 1.6.1