Main Page   Modules   Data Structures   File List   Data Fields   Globals  

uartsw.c

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

Generated on Sun Feb 22 19:12:31 2004 for Procyon AVRlib by doxygen1.3-rc2