Contiki 2.6
|
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 /*---------------------------------------------------------------------------*/