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

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