Main Page   Data Structures   File List   Data Fields   Globals  

/pwmsw.c

Go to the documentation of this file.
00001 /*! \file pwmsw.c \brief Software interrupt-driven multi-output PWM function library. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'pwmsw.c'
00005 // Title        : Software interrupt-driven multi-output PWM function library
00006 // Author       : Pascal Stang - Copyright (C) 2002
00007 // Created      : 7/20/2002
00008 // Revised      : 7/31/2002
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 #ifndef WIN32
00019     #include <avr/io.h>
00020 #endif
00021 
00022 #include "global.h"
00023 #include "pwmsw.h"
00024 
00025 // Program ROM constants
00026 
00027 // Global variables
00028 // PWM channel registers
00029 u16 PosTics;
00030 u16 PeriodTics;
00031 u08 Channel;
00032 SwPwmChannelType SwPwmChannels[SWPWM_NUM_CHANNELS];
00033 
00034 // functions
00035 
00036 // initializes software PWM system
00037 void pwmswInit(u16 periodTics)
00038 {
00039     u08 index;
00040 
00041     // attach the software PWM service routine to timer1 output compare A
00042     timerAttach(TIMER1OUTCOMPAREA_INT, pwmswService);
00043     // set PeriodTics
00044     PeriodTics = periodTics;
00045     // set PosTics
00046     PosTics = 0;
00047     // clear channels
00048     for(index=0; index<SWPWM_NUM_CHANNELS; index++)
00049     {
00050         SwPwmChannels[index].duty = 0;
00051         SwPwmChannels[index].setduty = 0;
00052     }
00053     // set initial interrupt time
00054     u16 OCValue;
00055     // read in current value of output compare register OCR1A
00056     OCValue =  inb(OCR1AL);     // read low byte of OCR1A
00057     OCValue += inb(OCR1AH)<<8;  // read high byte of OCR1A
00058     // increment OCR1A value by nextTics
00059     OCValue += PeriodTics; 
00060     // set future output compare time to this new value
00061     outb(OCR1AH, (OCValue>>8));         // write high byte
00062     outb(OCR1AL, (OCValue & 0x00FF));   // write low byte
00063 
00064     // enable the timer1 output compare A interrupt
00065     sbi(TIMSK, OCIE1A);
00066 }
00067 
00068 // turns off software PWM system
00069 void pwmswOff(void)
00070 {
00071     // disable the timer1 output compare A interrupt
00072     cbi(TIMSK, OCIE1A);
00073     // detach the service routine
00074     timerDetach(TIMER1OUTCOMPAREA_INT);
00075 }
00076 
00077 // set duty on channel
00078 void pwmswPWMSet(u08 channel, u16 duty)
00079 {
00080     // compare with max value of PeriodTics
00081     duty = MIN(duty, PeriodTics);
00082     SwPwmChannels[channel].setduty = duty;
00083 }
00084 
00085 void pwmswService(void)
00086 {
00087     u16 nextTics=PeriodTics;
00088     u08 index;
00089 
00090     // check for beginning of period
00091     if(PosTics == 0)
00092     {
00093         // examine all channels
00094         for(index=0; index<SWPWM_NUM_CHANNELS; index++)
00095         {
00096             // transfer set-duty to active-duty
00097             SwPwmChannels[index].duty = SwPwmChannels[index].setduty;
00098             // find next channel event to schedule
00099             //      if no channel has a duty setting greater than 0 (PosTics);
00100             //      nextTics will remain at PeriodTics for the next cycle
00101             if(SwPwmChannels[index].duty)
00102             {
00103                 nextTics = MIN(nextTics, SwPwmChannels[index].duty);
00104                 // set all non-zero channels to on
00105                 outb(SWPWMPORT, inb(SWPWMPORT) | (1<<index));
00106             }
00107         }
00108     }
00109     else
00110     {
00111         // examine all channels
00112         for(index=0; index<SWPWM_NUM_CHANNELS; index++)
00113         {
00114             // check if we have a duty cycle match
00115             if(PosTics == SwPwmChannels[index].duty)
00116             {
00117                 // clear output channel
00118                 outb(SWPWMPORT, inb(SWPWMPORT) & ~(1<<index));
00119             }
00120             // find next channel event to schedule
00121             //      if no channel has a duty setting greater than PosTics;
00122             //      nextTics will remain at PeriodTics and is handled below
00123             if(SwPwmChannels[index].duty > PosTics)
00124                 nextTics = MIN(nextTics, SwPwmChannels[index].duty-PosTics);
00125         }
00126         if(nextTics == PeriodTics)
00127         {
00128             // no more channels to schedule
00129             // schedule next cycle
00130             nextTics = PeriodTics - PosTics;
00131         }
00132     }
00133 
00134     // schedule next interrupt
00135     u16 OCValue;
00136     // read in current value of output compare register OCR1A
00137     OCValue =  inb(OCR1AL);     // read low byte of OCR1A
00138     OCValue += inb(OCR1AH)<<8;  // read high byte of OCR1A
00139     // increment OCR1A value by nextTics
00140     OCValue += nextTics;
00141 //  OCR1A+=nextTics;
00142     // set future output compare time to this new value
00143     outb(OCR1AH, (OCValue>>8));         // write high byte
00144     outb(OCR1AL, (OCValue & 0x00FF));   // write low byte
00145     // set our new tic position
00146     PosTics += nextTics;
00147     if(PosTics >= PeriodTics) PosTics -= PeriodTics;
00148 }
00149 

Generated on Fri Aug 1 10:42:42 2003 for Procyon AVRlib by doxygen1.2.18