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 }