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

uartsw2.c

Go to the documentation of this file.
00001 /*! \file uartsw2.c \brief Software Interrupt-driven UART Driver. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'uartsw2.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.6
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 
00021 #include "global.h"
00022 #include "timer.h"
00023 #include "uartsw2.h"
00024 
00025 // Program ROM constants
00026 
00027 // Global variables
00028 
00029 // uartsw transmit status and data variables
00030 static volatile u08 UartswTxBusy;
00031 static volatile u08 UartswTxData;
00032 static volatile u08 UartswTxBitNum;
00033 
00034 // baud rate common to transmit and receive
00035 static volatile u08 UartswBaudRateDiv;
00036 
00037 // uartsw receive status and data variables
00038 static volatile u08 UartswRxBusy;
00039 static volatile u08 UartswRxData;
00040 static volatile u08 UartswRxBitNum;
00041 // receive buffer
00042 static cBuffer uartswRxBuffer;               ///< uartsw receive buffer
00043 // automatically allocate space in ram for each buffer
00044 static char uartswRxData[UARTSW_RX_BUFFER_SIZE];
00045 
00046 // functions
00047 
00048 //! enable and initialize the software uart
00049 void uartswInit(void)
00050 {
00051     // initialize the buffers
00052     uartswInitBuffers();
00053     // initialize the ports
00054     sbi(UARTSW_TX_DDR, UARTSW_TX_PIN);
00055     #ifdef UARTSW_INVERT
00056     cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00057     #else
00058     sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00059     #endif
00060     cbi(UARTSW_RX_DDR, UARTSW_RX_PIN);
00061     cbi(UARTSW_RX_PORT, UARTSW_RX_PIN);
00062     // initialize baud rate
00063     uartswSetBaudRate(9600);
00064     
00065     // setup the transmitter
00066     UartswTxBusy = FALSE;
00067     // disable OC2 interrupt
00068     cbi(TIMSK, OCIE2);
00069     // attach TxBit service routine to OC2
00070     timerAttach(TIMER2OUTCOMPARE_INT, uartswTxBitService);
00071         
00072     // setup the receiver
00073     UartswRxBusy = FALSE;
00074     // disable OC0 interrupt
00075     cbi(TIMSK, OCIE0);
00076     // attach RxBit service routine to OC0
00077     timerAttach(TIMER0OUTCOMPARE_INT, uartswRxBitService);
00078     // INT2 trigger on rising/falling edge
00079     #ifdef UARTSW_INVERT
00080     sbi(MCUCSR, ISC2);  // rising edge
00081     #else
00082     cbi(MCUCSR, ISC2);  // falling edge
00083     #endif
00084     // enable INT2 interrupt
00085     sbi(GICR, INT2);
00086 
00087     // turn on interrupts
00088     sei();
00089 }
00090 
00091 //! create and initialize the uart buffers
00092 void uartswInitBuffers(void)
00093 {
00094     // initialize the UART receive buffer
00095     bufferInit(&uartswRxBuffer, uartswRxData, UARTSW_RX_BUFFER_SIZE);
00096 }
00097 
00098 //! turns off software UART
00099 void uartswOff(void)
00100 {
00101     // disable interrupts
00102     cbi(TIMSK, OCIE2);
00103     cbi(TIMSK, OCIE0);
00104     cbi(GICR, INT2);
00105     // detach the service routines
00106     timerDetach(TIMER2OUTCOMPARE_INT);
00107     timerDetach(TIMER0OUTCOMPARE_INT);
00108 }
00109 
00110 void uartswSetBaudRate(u32 baudrate)
00111 {
00112     u16 div;
00113 
00114     // set timer prescaler
00115     if( baudrate > (F_CPU/64L*256L) )
00116     {
00117         // if the requested baud rate is high,
00118         // set timer prescalers to div-by-64
00119         timer2SetPrescaler(TIMERRTC_CLK_DIV64);
00120         timer0SetPrescaler(TIMER_CLK_DIV64);
00121         div = 64;
00122     }
00123     else
00124     {
00125         // if the requested baud rate is low,
00126         // set timer prescalers to div-by-256
00127         timer2SetPrescaler(TIMERRTC_CLK_DIV256);
00128         timer0SetPrescaler(TIMER_CLK_DIV256);
00129         div = 256;
00130     }
00131 
00132     // calculate division factor for requested baud rate, and set it
00133     //UartswBaudRateDiv = (u08)(((F_CPU/64L)+(baudrate/2L))/(baudrate*1L));
00134     //UartswBaudRateDiv = (u08)(((F_CPU/256L)+(baudrate/2L))/(baudrate*1L));
00135     UartswBaudRateDiv = (u08)(((F_CPU/div)+(baudrate/2L))/(baudrate*1L));
00136 }
00137 
00138 //! returns the receive buffer structure 
00139 cBuffer* uartswGetRxBuffer(void)
00140 {
00141     // return rx buffer pointer
00142     return &uartswRxBuffer;
00143 }
00144 
00145 void uartswSendByte(u08 data)
00146 {
00147     // wait until uart is ready
00148     while(UartswTxBusy);
00149     // set busy flag
00150     UartswTxBusy = TRUE;
00151     // save data
00152     UartswTxData = data;
00153     // set number of bits (+1 for stop bit)
00154     UartswTxBitNum = 9;
00155     
00156     // set the start bit
00157     #ifdef UARTSW_INVERT
00158     sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00159     #else
00160     cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00161     #endif
00162     // schedule the next bit
00163     outb(OCR2, inb(TCNT2) + UartswBaudRateDiv);
00164     // enable OC2 interrupt
00165     sbi(TIMSK, OCIE2);
00166 }
00167 
00168 //! gets a byte (if available) from the uart receive buffer
00169 u08 uartswReceiveByte(u08* rxData)
00170 {
00171     // make sure we have a receive buffer
00172     if(uartswRxBuffer.size)
00173     {
00174         // make sure we have data
00175         if(uartswRxBuffer.datalength)
00176         {
00177             // get byte from beginning of buffer
00178             *rxData = bufferGetFromFront(&uartswRxBuffer);
00179             return TRUE;
00180         }
00181         else
00182         {
00183             // no data
00184             return FALSE;
00185         }
00186     }
00187     else
00188     {
00189         // no buffer
00190         return FALSE;
00191     }
00192 }
00193 
00194 void uartswTxBitService(void)
00195 {
00196     if(UartswTxBitNum)
00197     {
00198         // there are bits still waiting to be transmitted
00199         if(UartswTxBitNum > 1)
00200         {
00201             // transmit data bits (inverted, LSB first)
00202             #ifdef UARTSW_INVERT
00203             if( !(UartswTxData & 0x01) )
00204             #else
00205             if( (UartswTxData & 0x01) )
00206             #endif
00207                 sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00208             else
00209                 cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00210             // shift bits down
00211             UartswTxData = UartswTxData>>1;
00212         }
00213         else
00214         {
00215             // transmit stop bit
00216             #ifdef UARTSW_INVERT
00217             cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00218             #else
00219             sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
00220             #endif
00221         }
00222         // schedule the next bit
00223         outb(OCR2, inb(OCR2) + UartswBaudRateDiv);
00224         // count down
00225         UartswTxBitNum--;
00226     }
00227     else
00228     {
00229         // transmission is done
00230         // clear busy flag
00231         UartswTxBusy = FALSE;
00232         // disable OC2 interrupt
00233         cbi(TIMSK, OCIE2);
00234     }
00235 }
00236 
00237 void uartswRxBitService(void)
00238 {
00239     // this function runs on either:
00240     // - a rising edge interrupt
00241     // - Timer 0 output compare
00242     if(!UartswRxBusy)
00243     {
00244         // UART was not previously busy,
00245         // this must be is a start bit
00246         
00247         // disable INT2 interrupt
00248         cbi(GICR, INT2);
00249         // schedule data bit sampling 1.5 bit periods from now
00250         outb(OCR0, inb(TCNT0) + UartswBaudRateDiv + UartswBaudRateDiv/2);
00251         // clear OC0 interrupt flag
00252         sbi(TIFR, OCF0);
00253         // enable OC0 interrupt
00254         sbi(TIMSK, OCIE0);
00255         // set busy flag
00256         UartswRxBusy = TRUE;
00257         // reset bit counter
00258         UartswRxBitNum = 0;
00259         // reset data
00260         UartswRxData = 0;
00261     }
00262     else
00263     {
00264         // start bit has already been received
00265         // we're in the data bits
00266         
00267         // shift data byte to make room for new bit
00268         UartswRxData = UartswRxData>>1;
00269 
00270         // sample the data line
00271         #ifdef UARTSW_INVERT
00272         if( !(inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )
00273         #else
00274         if( (inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )
00275         #endif
00276         {
00277             // serial line is marking
00278             // record '1' bit
00279             UartswRxData |= 0x80;
00280         }
00281 
00282         // increment bit counter
00283         UartswRxBitNum++;
00284         // schedule next bit sample
00285         outb(OCR0, inb(OCR0) + UartswBaudRateDiv);
00286 
00287         // check if we have a full byte
00288         if(UartswRxBitNum >= 8)
00289         {
00290             // save data in receive buffer
00291             bufferAddToEnd(&uartswRxBuffer, UartswRxData);
00292             // disable OC0 interrupt
00293             cbi(TIMSK, OCIE0);
00294             // clear INT2 interrupt flag
00295             sbi(GIFR, INTF2);
00296             // enable INT interrupt
00297             sbi(GICR, INT2);
00298             // clear busy flag
00299             UartswRxBusy = FALSE;
00300         }
00301     }
00302 }
00303 
00304 SIGNAL(SIG_INTERRUPT2)
00305 {
00306     // run RxBit service routine
00307     uartswRxBitService();
00308 }

Generated on Sun Oct 29 03:41:08 2006 for Procyon AVRlib by  doxygen 1.4.2