Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

uartsw.c

Go to the documentation of this file.
00001 /*! \file uartsw.c \brief Software Interrupt-driven UART Driver. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'uartsw.c'
00005 // Title        : Software Interrupt-driven UART Driver
00006 // Author       : Pascal Stang - Copyright (C) 2002-2004
00007 // Created      : 7/20/2002
00008 // Revised      : 4/27/2004
00009 // Version      : 0.1
00010 // Target MCU   : Atmel AVR Series (intended for the ATmega16 and ATmega32)
00011 // Editor Tabs  : 4
00012 //
00013 // This code is distributed under the GNU Public License
00014 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00015 //
00016 //*****************************************************************************
00017 
00018 #include <avr/io.h>
00019 #include <avr/interrupt.h>
00020 #include <avr/signal.h>
00021 
00022 #include "global.h"
00023 #include "timer.h"
00024 #include "uartsw.h"
00025 
00026 // Program ROM constants
00027 
00028 // Global variables
00029 
00030 // uartsw transmit status and data variables
00031 static volatile u08 UartswTxBusy;
00032 static volatile u08 UartswTxData;
00033 static volatile u08 UartswTxBitNum;
00034 
00035 // baud rate common to transmit and receive
00036 static volatile u16 UartswBaudRateDiv;
00037 
00038 // uartsw receive status and data variables
00039 static volatile u08 UartswRxBusy;
00040 static volatile u08 UartswRxData;
00041 static volatile u08 UartswRxBitNum;
00042 // receive buffer
00043 static cBuffer uartswRxBuffer;               ///< uartsw receive buffer
00044 // automatically allocate space in ram for each buffer
00045 static char uartswRxData[UARTSW_RX_BUFFER_SIZE];
00046 
00047 // functions
00048 
00049 //! enable and initialize the software uart
00050 void uartswInit(void)
00051 {
00052     // initialize the buffers
00053     uartswInitBuffers();
00054     // initialize the ports
00055     sbi(UARTSW_TX_DDR, UARTSW_TX_PIN);
00056     cbi(UARTSW_RX_DDR, UARTSW_RX_PIN);
00057     cbi(UARTSW_RX_PORT, UARTSW_RX_PIN);
00058     // initialize baud rate
00059     uartswSetBaudRate(9600);
00060 
00061     // setup the transmitter
00062     UartswTxBusy = FALSE;
00063     // disable OC1A interrupt
00064     cbi(TIMSK, OCIE1A);
00065     // attach TxBit service routine to OC1A
00066     timerAttach(TIMER1OUTCOMPAREA_INT, uartswTxBitService);
00067 
00068     // setup the receiver
00069     UartswRxBusy = FALSE;
00070     // disable OC1B interrupt
00071     cbi(TIMSK, OCIE1B);
00072     // attach RxBit service routine to OC1B
00073     timerAttach(TIMER1OUTCOMPAREB_INT, uartswRxBitService);
00074     // attach RxBit service routine to ICP
00075     timerAttach(TIMER1INPUTCAPTURE_INT, uartswRxBitService);
00076     // trigger on rising edge
00077     sbi(TCCR1B, ICES1);
00078     // enable ICP interrupt
00079     sbi(TIMSK, TICIE1);
00080 
00081     // turn on interrupts
00082     sei();
00083 }
00084 
00085 //! create and initialize the uart buffers
00086 void uartswInitBuffers(void)
00087 {
00088     // initialize the UART receive buffer
00089     bufferInit(&uartswRxBuffer, uartswRxData, UARTSW_RX_BUFFER_SIZE);
00090 }
00091 
00092 //! turns off software UART
00093 void uartswOff(void)
00094 {
00095     // disable interrupts
00096     cbi(TIMSK, OCIE1A);
00097     cbi(TIMSK, OCIE1B);
00098     cbi(TIMSK, TICIE1);
00099     // detach the service routines
00100     timerDetach(TIMER1OUTCOMPAREA_INT);
00101     timerDetach(TIMER1OUTCOMPAREB_INT);
00102     timerDetach(TIMER1INPUTCAPTURE_INT);
00103 }
00104 
00105 void uartswSetBaudRate(u32 baudrate)
00106 {
00107     // set timer prescaler
00108     timer1SetPrescaler(TIMER_CLK_DIV1);
00109     // calculate division factor for requested baud rate, and set it
00110     UartswBaudRateDiv = (u16)((F_CPU+(baudrate/2L))/(baudrate*1L));
00111 }
00112 
00113 //! returns the receive buffer structure 
00114 cBuffer* uartswGetRxBuffer(void)
00115 {
00116     // return rx buffer pointer
00117     return &uartswRxBuffer;
00118 }
00119 
00120 void uartswSendByte(u08 data)
00121 {
00122     // wait until uart is ready
00123     while(UartswTxBusy);
00124     // set busy flag
00125     UartswTxBusy = TRUE;
00126     // save data
00127     UartswTxData = data;
00128     // set number of bits (+1 for stop bit)
00129     UartswTxBitNum = 9;
00130     
00131     // set the start bit
00132     #ifdef UARTSW_INVERT
00133     sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00134     #else
00135     cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00136     #endif
00137 
00138     // schedule the next bit
00139     outw(OCR1A, inw(TCNT1) + UartswBaudRateDiv);
00140     // enable OC1A interrupt
00141     sbi(TIMSK, OCIE1A);
00142 }
00143 
00144 //! gets a byte (if available) from the uart receive buffer
00145 u08 uartswReceiveByte(u08* rxData)
00146 {
00147     // make sure we have a receive buffer
00148     if(uartswRxBuffer.size)
00149     {
00150         // make sure we have data
00151         if(uartswRxBuffer.datalength)
00152         {
00153             // get byte from beginning of buffer
00154             *rxData = bufferGetFromFront(&uartswRxBuffer);
00155             return TRUE;
00156         }
00157         else
00158         {
00159             // no data
00160             return FALSE;
00161         }
00162     }
00163     else
00164     {
00165         // no buffer
00166         return FALSE;
00167     }
00168 }
00169 
00170 void uartswTxBitService(void)
00171 {
00172     if(UartswTxBitNum)
00173     {
00174         // there are bits still waiting to be transmitted
00175         if(UartswTxBitNum > 1)
00176         {
00177             // transmit data bits (inverted, LSB first)
00178             #ifdef UARTSW_INVERT
00179             if( !(UartswTxData & 0x01) )
00180             #else
00181             if( (UartswTxData & 0x01) )
00182             #endif
00183                 sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00184             else
00185                 cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00186             // shift bits down
00187             UartswTxData = UartswTxData>>1;
00188         }
00189         else
00190         {
00191             // transmit stop bit
00192             #ifdef UARTSW_INVERT
00193             cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00194             #else
00195             sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00196             #endif
00197         }
00198         // schedule the next bit
00199         outw(OCR1A, inw(OCR1A) + UartswBaudRateDiv);
00200         // count down
00201         UartswTxBitNum--;
00202     }
00203     else
00204     {
00205         // transmission is done
00206         // clear busy flag
00207         UartswTxBusy = FALSE;
00208     }
00209 }
00210 
00211 void uartswRxBitService(void)
00212 {
00213     // this function runs on either:
00214     // - a rising edge interrupt
00215     // - OC1B
00216     if(!UartswRxBusy)
00217     {
00218         // this is a start bit
00219         // disable ICP interrupt
00220         cbi(TIMSK, TICIE1);
00221         // schedule data bit sampling 1.5 bit periods from now
00222         outw(OCR1B, inw(TCNT1) + UartswBaudRateDiv + UartswBaudRateDiv/2);
00223         // clear OC1B interrupt flag
00224         sbi(TIFR, OCF1B);
00225         // enable OC1B interrupt
00226         sbi(TIMSK, OCIE1B);
00227         // set start bit flag
00228         UartswRxBusy = TRUE;
00229         // reset bit counter
00230         UartswRxBitNum = 0;
00231         // reset data
00232         UartswRxData = 0;
00233     }
00234     else
00235     {
00236         // start bit has already been received
00237         // we're in the data bits
00238         
00239         // shift data byte to make room for new bit
00240         UartswRxData = UartswRxData>>1;
00241 
00242         // sample the data line
00243         #ifdef UARTSW_INVERT
00244         if( !(inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )
00245         #else
00246         if( !(inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )
00247         #endif
00248         {
00249             // serial line is marking
00250             // record '1' bit
00251             UartswRxData |= 0x80;
00252         }
00253 
00254         // increment bit counter
00255         UartswRxBitNum++;
00256         // schedule next bit sample
00257         outw(OCR1B, inw(OCR1B) + UartswBaudRateDiv);
00258 
00259         // check if we have a full byte
00260         if(UartswRxBitNum >= 8)
00261         {
00262             // save data in receive buffer
00263             bufferAddToEnd(&uartswRxBuffer, UartswRxData);
00264             // disable OC1B interrupt
00265             cbi(TIMSK, OCIE1B);
00266             // clear ICP interrupt flag
00267             sbi(TIFR, ICF1);
00268             // enable ICP interrupt
00269             sbi(TIMSK, TICIE1);
00270             // clear start bit flag
00271             UartswRxBusy = FALSE;
00272         }
00273     }
00274 }
00275 
00276 /*
00277 void uartswRxBitService(void)
00278 {
00279     u16 thisBitTime;
00280     u08 bitperiods;
00281     u08 i;
00282 
00283     // bit transition was detected
00284     // record bit's edge time
00285     thisBitTime = inw(ICR1);
00286 
00287     cbi(PORTB, 0);
00288 
00289     if(!UartswRxStartBit)
00290     {
00291         // this is a start bit
00292         // switch to falling-edge trigger
00293         cbi(TCCR1B, ICES1);
00294         // record bit time
00295         UartswRxBitTime = thisBitTime;
00296         // set start bit flag
00297         UartswRxStartBit = TRUE;
00298         // reset bit counter
00299         UartswRxBitNum = 0;
00300         // reset data
00301         UartswRxData = 0;
00302     }
00303     else
00304     {
00305         // start bit has already been received
00306         // we're in the data bits
00307         
00308         // how many bit periods since last edge?
00309         bitperiods = (thisBitTime - UartswRxBitTime + UartswBaudRateDiv/2)/UartswBaudRateDiv;
00310         // set last edge time
00311         UartswRxBitTime = thisBitTime;
00312 
00313         if(bitperiods > 10)
00314         {
00315             // switch to trigger on rising edge
00316             sbi(TCCR1B, ICES1);
00317             // clear start bit flag
00318             UartswRxStartBit = FALSE;
00319         }
00320         else
00321         {
00322 
00323 
00324         if( inb(TCCR1B) & (1<<ICES1) )
00325         {
00326             // just triggered on a rising edge
00327             // previous bits were zero
00328             // shift in the data (data bits are inverted)
00329             for(i=0; i<bitperiods; i++)
00330             {
00331                 UartswRxData = UartswRxData<<1;
00332                 UartswRxData |= 0x01;
00333             }
00334             // switch to trigger on falling edge
00335             cbi(TCCR1B, ICES1);
00336         }
00337         else
00338         {
00339             // just triggered on a falling edge
00340             // previous bits were one
00341             // shift in the data (data bits are inverted)
00342             for(i=0; i<bitperiods; i++)
00343             {
00344                 UartswRxData = UartswRxData<<1;
00345             }
00346             // switch to trigger on rising edge
00347             sbi(TCCR1B, ICES1);
00348         }
00349         
00350         // increment bit counter
00351         UartswRxBitNum += bitperiods;
00352         
00353         // check if we have a full byte + start bit
00354         if(bitperiods > 8)
00355         {
00356             // save data in receive buffer
00357             bufferAddToEnd(&uartswRxBuffer, UartswRxData);
00358             // switch to trigger on rising edge
00359             sbi(TCCR1B, ICES1);
00360             // clear start bit flag
00361             UartswRxStartBit = FALSE;
00362         }
00363         }
00364     }
00365 
00366     // turn off debug LEDs
00367     delay(10);
00368     sbi(PORTB, 0);
00369     sbi(PORTB, 1);
00370 }
00371 */

Generated on Tue Sep 20 03:11:43 2005 for Procyon AVRlib by  doxygen 1.4.2