Contiki 2.6

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 "contiki.h"
00037 #include "sys/energest.h"
00038 #include "dev/uart1.h"
00039 #include "dev/watchdog.h"
00040 #include "sys/ctimer.h"
00041 #include "lib/ringbuf.h"
00042 #include "isr_compat.h"
00043 
00044 static int (*uart1_input_handler)(unsigned char c);
00045 static volatile uint8_t rx_in_progress;
00046 
00047 static volatile uint8_t transmitting;
00048 
00049 #ifdef UART1_CONF_TX_WITH_INTERRUPT
00050 #define TX_WITH_INTERRUPT UART1_CONF_TX_WITH_INTERRUPT
00051 #else /* UART1_CONF_TX_WITH_INTERRUPT */
00052 #define TX_WITH_INTERRUPT 0
00053 #endif /* UART1_CONF_TX_WITH_INTERRUPT */
00054 
00055 #ifdef UART1_CONF_RX_WITH_DMA
00056 #define RX_WITH_DMA UART1_CONF_RX_WITH_DMA
00057 #else /* UART1_CONF_RX_WITH_DMA */
00058 #define RX_WITH_DMA 1
00059 #endif /* UART1_CONF_RX_WITH_DMA */
00060 
00061 #if TX_WITH_INTERRUPT
00062 #define TXBUFSIZE 128
00063 
00064 static struct ringbuf txbuf;
00065 static uint8_t txbuf_data[TXBUFSIZE];
00066 #endif /* TX_WITH_INTERRUPT */
00067 
00068 #if RX_WITH_DMA
00069 #define RXBUFSIZE 128
00070 
00071 static uint8_t rxbuf[RXBUFSIZE];
00072 static uint16_t last_size;
00073 static struct ctimer rxdma_timer;
00074 
00075 static void
00076 handle_rxdma_timer(void *ptr)
00077 {
00078   uint16_t size;
00079   size = DMA0SZ; /* Note: loop requires that size is less or eq to RXBUFSIZE */
00080   while(last_size != size) {
00081 /*     printf("read: %c [%d,%d]\n", (unsigned char)rxbuf[RXBUFSIZE - last_size], */
00082 /*         last_size, size); */
00083     uart1_input_handler((unsigned char)rxbuf[RXBUFSIZE - last_size]);
00084     last_size--;
00085     if(last_size == 0) last_size = RXBUFSIZE;
00086   }
00087 
00088   ctimer_reset(&rxdma_timer);
00089 }
00090 #endif /* RX_WITH_DMA */
00091 
00092 /*---------------------------------------------------------------------------*/
00093 uint8_t
00094 uart1_active(void)
00095 {
00096   return ((~ UTCTL1) & TXEPT) | rx_in_progress | transmitting;
00097 }
00098 /*---------------------------------------------------------------------------*/
00099 void
00100 uart1_set_input(int (*input)(unsigned char c))
00101 {
00102 #if RX_WITH_DMA /* This needs to be called after ctimer process is started */
00103   ctimer_set(&rxdma_timer, CLOCK_SECOND/64, handle_rxdma_timer, NULL);
00104 #endif
00105   uart1_input_handler = input;
00106 }
00107 /*---------------------------------------------------------------------------*/
00108 void
00109 uart1_writeb(unsigned char c)
00110 {
00111   watchdog_periodic();
00112 #if TX_WITH_INTERRUPT
00113 
00114   /* Put the outgoing byte on the transmission buffer. If the buffer
00115      is full, we just keep on trying to put the byte into the buffer
00116      until it is possible to put it there. */
00117   while(ringbuf_put(&txbuf, c) == 0);
00118 
00119   /* If there is no transmission going, we need to start it by putting
00120      the first byte into the UART. */
00121   if(transmitting == 0) {
00122     transmitting = 1;
00123 
00124     /* Loop until the transmission buffer is available. */
00125     /*while((IFG2 & UTXIFG1) == 0);*/
00126     TXBUF1 = ringbuf_get(&txbuf);
00127   }
00128 
00129 #else /* TX_WITH_INTERRUPT */
00130 
00131   /* Loop until the transmission buffer is available. */
00132   while((IFG2 & UTXIFG1) == 0);
00133 
00134   /* Transmit the data. */
00135   TXBUF1 = c;
00136 #endif /* TX_WITH_INTERRUPT */
00137 }
00138 /*---------------------------------------------------------------------------*/
00139 /**
00140  * Initalize the RS232 port.
00141  *
00142  */
00143 void
00144 uart1_init(unsigned long ubr)
00145 {
00146   /* RS232 */
00147   P3DIR &= ~0x80;                       /* Select P37 for input (UART1RX) */
00148   P3DIR |= 0x40;                        /* Select P36 for output (UART1TX) */
00149   P3SEL |= 0xC0;                        /* Select P36,P37 for UART1{TX,RX} */
00150 
00151   UCTL1 = SWRST | CHAR;                 /* 8-bit character, UART mode */
00152 
00153 #if 0
00154   U1RCTL &= ~URXEIE; /* even erroneous characters trigger interrupts */
00155 #endif
00156 
00157   UTCTL1 = SSEL1;                       /* UCLK = MCLK */
00158 
00159   UBR01 = ubr;
00160   UBR11 = ubr >> 8;
00161   /*
00162    * UMCTL1 values calculated using
00163    * http://mspgcc.sourceforge.net/baudrate.html
00164    */
00165   switch(ubr) {
00166 
00167 #if F_CPU == 3900000ul
00168 
00169   case UART1_BAUD2UBR(115200ul):
00170     UMCTL1 = 0xF7;
00171     break;
00172   case UART1_BAUD2UBR(57600ul):
00173     UMCTL1 = 0xED;
00174     break;
00175   case UART1_BAUD2UBR(38400ul):
00176     UMCTL1 = 0xD6;
00177     break;
00178   case UART1_BAUD2UBR(19200ul):
00179     UMCTL1 = 0x08;
00180     break;
00181   case UART1_BAUD2UBR(9600ul):
00182     UMCTL1 = 0x22;
00183     break;
00184 
00185 #elif F_CPU == 2457600ul
00186 
00187   case UART1_BAUD2UBR(115200ul):
00188     UMCTL1 = 0x4A;
00189     break;
00190   case UART1_BAUD2UBR(57600ul):
00191     UMCTL1 = 0x5B;
00192     break;
00193   default:
00194     /* 9600, 19200, 38400 don't require any correction */
00195     UMCTL1 = 0x00;
00196 
00197 #else
00198 
00199 #error Unsupported CPU speed in uart1.c
00200 
00201 #endif
00202   }
00203 
00204   ME2 &= ~USPIE1;                       /* USART1 SPI module disable */
00205   ME2 |= (UTXE1 | URXE1);               /* Enable USART1 TXD/RXD */
00206 
00207   UCTL1 &= ~SWRST;
00208 
00209   /* XXX Clear pending interrupts before enable!!! */
00210   IFG2 &= ~URXIFG1;
00211   U1TCTL |= URXSE;
00212 
00213   rx_in_progress = 0;
00214 
00215   transmitting = 0;
00216 
00217   IE2 |= URXIE1;                        /* Enable USART1 RX interrupt  */
00218 #if TX_WITH_INTERRUPT
00219   ringbuf_init(&txbuf, txbuf_data, sizeof(txbuf_data));
00220   IE2 |= UTXIE1;                        /* Enable USART1 TX interrupt  */
00221 #endif /* TX_WITH_INTERRUPT */
00222 
00223 #if RX_WITH_DMA
00224   IE2 &= ~URXIE1; /* disable USART1 RX interrupt  */
00225   /* UART1_RX trigger */
00226   DMACTL0 = DMA0TSEL_9;
00227 
00228   /* source address = RXBUF1 */
00229   DMA0SA = (unsigned int) &RXBUF1;
00230   DMA0DA = (unsigned int) &rxbuf;
00231   DMA0SZ = RXBUFSIZE;
00232   last_size = RXBUFSIZE;
00233   DMA0CTL = DMADT_4 + DMASBDB + DMADSTINCR_3 + DMAEN + DMAREQ;// DMAIE;
00234 
00235   msp430_add_lpm_req(MSP430_REQUIRE_LPM1);
00236 #endif /* RX_WITH_DMA */
00237 }
00238 /*---------------------------------------------------------------------------*/
00239 #if !RX_WITH_DMA
00240 ISR(UART1RX, uart1_rx_interrupt)
00241 {
00242   uint8_t c;
00243   ENERGEST_ON(ENERGEST_TYPE_IRQ);
00244 
00245   if(!(URXIFG1 & IFG2)) {
00246     /* Edge detect if IFG not set? */
00247     U1TCTL &= ~URXSE; /* Clear the URXS signal */
00248     U1TCTL |= URXSE;  /* Re-enable URXS - needed here?*/
00249     rx_in_progress = 1;
00250     LPM4_EXIT;
00251   } else {
00252     rx_in_progress = 0;
00253     /* Check status register for receive errors. */
00254     if(URCTL1 & RXERR) {
00255       c = RXBUF1;   /* Clear error flags by forcing a dummy read. */
00256     } else {
00257       c = RXBUF1;
00258       if(uart1_input_handler != NULL) {
00259         if(uart1_input_handler(c)) {
00260           LPM4_EXIT;
00261         }
00262       }
00263     }
00264   }
00265 
00266   ENERGEST_OFF(ENERGEST_TYPE_IRQ);
00267 }
00268 #endif /* !RX_WITH_DMA */
00269 /*---------------------------------------------------------------------------*/
00270 #if TX_WITH_INTERRUPT
00271 ISR(UART1TX, uart1_tx_interrupt)
00272 {
00273   ENERGEST_ON(ENERGEST_TYPE_IRQ);
00274 
00275   if(ringbuf_elements(&txbuf) == 0) {
00276     transmitting = 0;
00277   } else {
00278     TXBUF1 = ringbuf_get(&txbuf);
00279   }
00280 
00281   ENERGEST_OFF(ENERGEST_TYPE_IRQ);
00282 }
00283 #endif /* TX_WITH_INTERRUPT */
00284 /*---------------------------------------------------------------------------*/