Contiki 2.6

uart.c

Go to the documentation of this file.
00001 /** @file hal/micro/cortexm3/uart.c
00002  * @brief STM32W  uart drivers, supporting IAR's standard library
00003  *        IO routines.
00004  *
00005  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved.        -->
00006  */
00007 
00008 #include PLATFORM_HEADER
00009 #include "hal/micro/micro-common.h"
00010 #include "hal/micro/cortexm3/micro-common.h"
00011 #include "uart.h"
00012 #ifdef __GNUC__
00013 #include <sys/stat.h>
00014 #include <stdio.h>
00015 #define _LLIO_STDIN ((int) stdin)
00016 #define _LLIO_STDOUT ((int) stdout)
00017 #define _LLIO_STDERR ((int) stderr)
00018 #define _LLIO_ERROR  (-1)
00019 #define __write _write
00020 #define __read _read
00021 #undef putchar
00022 void __io_putchar( char c );
00023 int putchar (int c)
00024 {
00025   __io_putchar((char) c);
00026   return c;
00027 }
00028 #endif
00029 #define RECEIVE_QUEUE_SIZE (128)
00030 
00031 int8u rxQ[RECEIVE_QUEUE_SIZE];
00032 int16u rxHead;
00033 int16u rxTail;
00034 int16u rxUsed;
00035 
00036 //////////////////////////////////////////////////////////////////////////////
00037 // Initialization
00038 
00039 void uartInit(int32u baudrate, int8u databits, SerialParity parity, int8u stopbits)
00040 {
00041   int32u tempcfg;
00042   int32u tmp;
00043   
00044   assert( (baudrate >= 300) && (baudrate <=921600) );
00045     
00046   tmp = (2*12000000L + baudrate/2) / baudrate;
00047   SC1_UARTFRAC = tmp & 1;
00048   SC1_UARTPER = tmp / 2;
00049   
00050   if(databits == 7) {
00051     tempcfg = 0;
00052   } else {
00053     tempcfg = SC_UART8BIT;
00054   }
00055   
00056   if (parity == PARITY_ODD) {
00057     tempcfg |= SC_UARTPAR | SC_UARTODD;
00058   } else if( parity == PARITY_EVEN ) {
00059     tempcfg |= SC_UARTPAR;
00060   }
00061 
00062   if ((stopbits & 0x0F) >= 2) {
00063     tempcfg |= SC_UART2STP;
00064   }
00065   SC1_UARTCFG = tempcfg;
00066 
00067   SC1_MODE = SC1_MODE_UART;
00068 
00069   rxHead=0;
00070   rxTail=0;
00071   rxUsed=0;
00072 
00073   halGpioConfig(PORTB_PIN(1),GPIOCFG_OUT_ALT);
00074   halGpioConfig(PORTB_PIN(2),GPIOCFG_IN);
00075 
00076   // Make the RX Valid interrupt level sensitive (instead of edge)
00077   SC1_INTMODE = SC_RXVALLEVEL;
00078   // Enable just RX interrupts; TX interrupts are controlled separately
00079   INT_SC1CFG |= (INT_SCRXVAL   |
00080                  INT_SCRXOVF   |
00081                  INT_SC1FRMERR |
00082                  INT_SC1PARERR);
00083   INT_SC1FLAG = 0xFFFF; // Clear any stale interrupts
00084   INT_CFGSET = INT_SC1;
00085 }
00086 
00087 //////////////////////////////////////////////////////////////////////////////
00088 // Transmit
00089 
00090 // IAR Standard library hook for serial output
00091 size_t __write(int handle, const unsigned char * buffer, size_t size)
00092 {
00093   size_t nChars = 0;
00094 
00095   /* This template only writes to "standard out" and "standard err",
00096    * for all other file handles it returns failure. */
00097   if (handle != _LLIO_STDOUT && handle != _LLIO_STDERR) {
00098     return _LLIO_ERROR;
00099   }
00100 
00101   if (buffer == 0) {
00102     // This means that we should flush internal buffers.  
00103     //spin until TX complete (TX is idle)
00104     while ((SC1_UARTSTAT&SC_UARTTXIDLE)!=SC_UARTTXIDLE) {}
00105     return 0;
00106   }
00107   
00108   // ensure port is configured for UART
00109   if(SC1_MODE != SC1_MODE_UART) {
00110     return _LLIO_ERROR;
00111   }
00112 
00113   while(size--) {
00114     //spin until data register has room for more data
00115     while ((SC1_UARTSTAT&SC_UARTTXFREE)!=SC_UARTTXFREE) {}
00116     SC1_DATA = *buffer;
00117     buffer++;
00118 
00119     ++nChars;
00120   }
00121 
00122   return nChars;
00123 }
00124 #ifdef __GNUC__
00125 int fflush (FILE *f)
00126 #endif
00127 #ifdef __ICCARM__
00128 size_t fflush(int handle)
00129 #endif
00130 {
00131   return __write(_LLIO_STDOUT, NULL, 0);
00132 }
00133 
00134 static void halInternalUart1TxIsr(void)
00135 {
00136   // Nothing for now, as ouput is blocking from the __write function
00137 }
00138 
00139 
00140 //////////////////////////////////////////////////////////////////////////////
00141 // Receive
00142 
00143 // IAR Standard library hook for serial input
00144 size_t __read(int handle, unsigned char * buffer, size_t size)
00145 {
00146   int nChars = 0;
00147 
00148   /* This template only reads from "standard in", for all other file
00149    * handles it returns failure. */
00150   if (handle != _LLIO_STDIN)
00151   {
00152     return _LLIO_ERROR;
00153   }
00154 
00155   for(nChars = 0; (rxUsed>0) && (nChars < size); nChars++) {
00156     ATOMIC(
00157       *buffer++ = rxQ[rxTail];
00158       rxTail = (rxTail+1) % RECEIVE_QUEUE_SIZE;
00159       rxUsed--;
00160     )
00161   }
00162 
00163   return nChars;
00164 }
00165 
00166 static void halInternalUart1RxIsr(void)
00167 {
00168 
00169   // At present we really don't care which interrupt(s)
00170   // occurred, just that one did.  Loop reading RXVALID
00171   // data, processing any errors noted
00172   // along the way.
00173   while ( SC1_UARTSTAT & SC_UARTRXVAL ) {
00174     int8u errors = SC1_UARTSTAT & (SC_UARTFRMERR |
00175                                    SC_UARTRXOVF  |
00176                                    SC_UARTPARERR );
00177     int8u incoming = (int8u) SC1_DATA;
00178 
00179     if ( (errors == 0) && (rxUsed < (RECEIVE_QUEUE_SIZE-1)) ) {
00180       rxQ[rxHead] = incoming;
00181       rxHead = (rxHead+1) % RECEIVE_QUEUE_SIZE;
00182       rxUsed++;
00183     } else {
00184       // IAR standard library doesn't allow for any error handling in the 
00185       //  case of rx errors or not having space in the receive queue, so the
00186       //  errors are just silently dropped.
00187     }
00188   } // end of while ( SC1_UARTSTAT & SC1_UARTRXVAL )
00189 }
00190 
00191 
00192 //////////////////////////////////////////////////////////////////////////////
00193 // Interrupts
00194 
00195 void halSc1Isr(void)
00196 {
00197   int32u interrupt;
00198 
00199   //this read and mask is performed in two steps otherwise the compiler
00200   //will complain about undefined order of volatile access
00201   interrupt = INT_SC1FLAG;
00202   interrupt &= INT_SC1CFG;
00203   
00204   while (interrupt != 0) {
00205   
00206     INT_SC1FLAG = interrupt; // acknowledge the interrupts early
00207 
00208     // RX events
00209     if ( interrupt & (INT_SCRXVAL   | // RX has data
00210                       INT_SCRXOVF   | // RX Overrun error
00211                       INT_SC1FRMERR | // RX Frame error
00212                       INT_SC1PARERR ) // RX Parity error
00213        ) {
00214       halInternalUart1RxIsr();
00215     }
00216     
00217     // TX events
00218     if ( interrupt & (INT_SCTXFREE | // TX has room
00219                       INT_SCTXIDLE ) // TX idle (more room)
00220        ) {
00221       halInternalUart1TxIsr();
00222     }
00223 
00224     interrupt = INT_SC1FLAG;
00225     interrupt &= INT_SC1CFG;
00226   }
00227 }
00228 
00229 /*******************************************************************************
00230 * Function Name  : __io_getcharNonBlocking
00231 * Description    : Non blocking read 
00232 * Input          : none
00233 * Output         : dataByte: buffer containing the read byte if any
00234 * Return         : TRUE if there is a data, FALSE otherwise
00235 *******************************************************************************/
00236 boolean __io_getcharNonBlocking(int8u *data)
00237 {
00238   if (__read(_LLIO_STDIN,data,1))
00239     return TRUE;
00240   else
00241     return FALSE;
00242 }/* end serialReadByte() */
00243 
00244 void __io_putchar( char c )
00245 {
00246   __write(_LLIO_STDOUT, (unsigned char *)&c, 1);
00247 }
00248 
00249 int __io_getchar()
00250 {
00251   unsigned char c;
00252   __read(_LLIO_STDIN, &c, 1);
00253   return (int)(c);
00254 }
00255 
00256 void __io_flush( void )
00257 {
00258   __write(_LLIO_STDOUT, NULL, 0);
00259 }