Subversion Repositories FlightCtrl

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*****************************************************************************************************************************
* File:                 timer0.c
*
* Purpose:              setup of timer0 and timer2
*                               and delay functions
*
* Functions:    void Timer_Init(void);
*                               void TIMER2_Init(void);
*                               void Delay_ms(unsigned int);
*                               void Delay_ms_Mess(unsigned int);
*
*****************************************************************************************************************************/

//

#include "main.h"

volatile unsigned int CountMilliseconds = 0;
volatile static unsigned int tim_main;
volatile unsigned char UpdateMotor = 0;
volatile unsigned int cntKompass = 0;
volatile unsigned int beeptime = 0;
volatile unsigned char SendSPI = 0;
volatile unsigned char ServoActive = 0;

unsigned int BeepMuster = 0xFFFF;

volatile int16_t        ServoNickValue = 0;
volatile int16_t        ServoRollValue = 0;


//---------------------------
enum
{
        STOP             = 0,
        CK               = 1,
        CK8              = 2,
        CK64             = 3,
        CK256            = 4,
        CK1024           = 5,
        T0_FALLING_EDGE  = 6,
        T0_RISING_EDGE   = 7
};
//---------------------------



//********************************************************************************************************************
// Timer0 is running with "fast PWM" at OC0A=PORTB3 and OC0B=PORTB4
// setup of Offset P_OFF1 and P_OFF2 for the air pressure sensor
//--------------------------------------------------------------------------------------------------------------------
void Timer_Init(void)
{
        tim_main = SetDelay(10);
       
        // ----------------------------------------------------------------------------------------------------------------
        // TCCR0B – Timer/Counter Control Register B containing: FOC0A FOC0B – – WGM02 CS02 CS01 CS0
        //
        TCCR0B = CK8;                                                                   // CK8 = 2 = clk/8 (From prescaler) one turnarround takes 0.1024ms
       
        // ----------------------------------------------------------------------------------------------------------------
        // TCCR0A – Timer/Counter Control Register A containing: COM0A1 COM0A0 COM0B1 COM0B0 – – WGM01 WGM00
        //
        TCCR0A = (1<<COM0A1)|(1<<COM0B1)|3;                     // WGM02 WGM01 WGM00 = 011 = Fast PWM
       
        OCR0A =  0;                                                                             // output compare Register A for Counter 0
        OCR0B = 120;                                                                    // output compare Register B for Counter 0
       
        TCNT0 = (unsigned char)-TIMER_RELOAD_VALUE;     // reload       // #define TIMER_RELOAD_VALUE  250
       
        // ----------------------------------------------------------------------------------------------------------------
        // TIMSK0 – Timer/Counter Interrupt Mask Register containing: – – – – – OCIE0B OCIE0A TOIE0
        // TOIE0: Timer/Counter0 Overflow Interrupt Enable - When the TOIE0 bit is written to one, and the I-bit in the Status Register is set
        //
        TIMSK0 |= (1<<TOIE0);
}
// **************************** EOF: void Timer_Init(void) *******************************************************************



// *************************************************************************************************************************
// this funktions returns the variable "CountMilliseconds" as it will be after the waiting time hase been exipired
// -------------------------------------------------------------------------------------------------------------------------
unsigned int SetDelay(unsigned int t)
{
        return(CountMilliseconds + t + 1);
}
// *************************************************************************************************************************




// *************************************************************************************************************************
// Hier wird also die Zeitdifferenz (t-CountsMilliseconds) mit der Maske 0x08000 maskiert.
// 0x8000 = 1000 0000 0000 0000 setzt also bis auf das höchste Bit der 16-bit Zeitdifferenz alle Bits auf 0.
// Bei einer Integerzahl codiert das höchst bit das Vorzeichen. Ist also t < CountMillisconds wird,
// so flippt das Vorzeichen-Bit auf 1 sonst ist es 0. Diese Eigenschaft wird hier genutzt.
// Das Ganze wird dann noch um 9 Bits nach rechts geshiftet, damit die Information im unteren Byte liegt,
// um beim Typecast des Rückgabewertes auf 8-Bit die Ändeurng im oberen Byte nicht abgeschnitten wird.
//
// Man könnte den Code auch so aufschreiben:
/*
char CheckDelay(unsigned int t)
{
        int diff;
        diff = int(t-CountMilliseconds);
        if (diff < 0) return 255;
        else return 0;
}
*/

//
char CheckDelay(unsigned int t)
{
        return(((t - CountMilliseconds) & 0x8000) >> 9);                // 0x8000 = 0b 1000 0000 0000 0000
}
// *************************************************************************************************************************



// *************************************************************************************************************************
void Delay_ms(unsigned int w)
{
        unsigned int akt;
       
        akt = SetDelay(w);
        while (!CheckDelay(akt));
}
// *************************************************************************************************************************



// *************************************************************************************************************************
void Delay_ms_Mess(unsigned int w)
{
        unsigned int akt;
        akt = SetDelay(w);
        while (!CheckDelay(akt)) if(AdReady) {AdReady = 0; ANALOG_ON;}          // #define ANALOG_ON ADCSRA=(1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADIE)
}
// *************************************************************************************************************************



// *************************************************************************************************************************
// Interrupt due to overflow of Timer0
// --------------------------------------
ISR(TIMER0_OVF_vect)                                                   
{
        static unsigned char cnt_1ms=1, cnt=0;          // one turnarround of Timer0 takes 0.1024ms at 256 steps
        unsigned char pieper_ein = 0;
       
        if(SendSPI) SendSPI--;                                          //
       
        if(!cnt--)
        {
                cnt=9;                                                                  // 10 steps * 0.1024ms -> 1ms
                cnt_1ms++;                                                             
                cnt_1ms %= 2;                                                   // modulo division
                if(!cnt_1ms) UpdateMotor = 1;                   // all 2 ms the motor is updated
                CountMilliseconds++;
        }
       
        if(beeptime >= 1)
        {
                beeptime--;
                if(beeptime & BeepMuster)
                {
                        pieper_ein = 1;
                }
                else pieper_ein = 0;
        }
        else
        {
                pieper_ein = 0;
                BeepMuster = 0xFFFF;
        }
       
        if(pieper_ein)
        {
                PORTC |= (1<<7);                                                                // beeper is connected to PORTC.7
        }
        else
        {
                PORTC &= ~(1<<7);
        }
       
        //------------------------------------------------------------------------------------------------------------------------
        // Compass works per PWM at PORTC4
        //------------------------------------------------------------------------------------------------------------------------
        if(EE_Parameter.GlobalConfig & CFG_KOMPASS_AKTIV)
        {
                if(PINC & 0x10)                                                                 // PORTC4 is up
                {
                        cntKompass++;
                }
                else                                                                                    // PORTC4 is doing down now -> check lenght of PWM pulse
                {
                        if((cntKompass) && (cntKompass < 362))          // if value is positiv and less then 362
                        {
                                cntKompass += cntKompass / 41;
                                if(cntKompass > 10) KompassValue = cntKompass - 10; else KompassValue = 0;              // indicated value of compass
                        }
                        KompassRichtung = ((540 + KompassValue - KompassStartwert) % 360) - 180;                        // differential direction
                        cntKompass = 0;                                                                                                                                         // reset PWM counter
                }      
        }

}
// *************************************************************************************************************************




// *************************************************************************************************************************
// Purpose:     Initialize Timer 2
//
// Timer 2 is used to generate the PWM at PD7 (J7) to control a camera servo for nick compensation.
//
//---------------------------------------------------------------------------------------------------------------------------------------
void TIMER2_Init(void)
{
        unsigned char sreg = SREG;      // copy SREG – Status Register
       
        cli();                                          // disable all interrupts before reconfiguration
       
        PORTD &= ~(1<<PORTD7);  // set PD7 = OC2A to low = Servo PPM
       
        //------------------------------------------------------------------------------------------
        // DDRC – Port C Data Direction Register containing: DDC7 DDC6 DDC5 DDC4 DDC3 DDC2 DDC1 DDC0
        DDRC  |= (1<<DDC6);             // set PC6 as output (Reset for HEF4017)
        HEF4017R_ON;                            // #define HEF4017R_ON     PORTC |=  (1<<PORTC6)
       
        //------------------------------------------------------------------------------------------
        // TCCR2A = Timer/Counter 2 Control Register A containing: COM2A1 COM2A0 COM2B1 COM2B0 – – WGM21 WGM20
        // COM2A1:0: Compare Match Output A Mode. These bits control the Output Compare pin (OC2A) behavior
        // COM2B1:0: Compare Match Output B Mode. These bits control the Output Compare pin (OC2B) behavior
        TCCR2A &= ~((1<<COM2A1)|(1<<COM2A0)|(1<<COM2B1)|(1<<COM2B0));   // Normal port operation
        //
        // The counter counts from BOTTOM to TOP then restarts from BOTTOM.
        // TOP is defined as OCR2A asxxx, MGM22:0 = 111.
        TCCR2A |= (1<<WGM21)|(1<<WGM20);
       
        //------------------------------------------------------------------------------------------
        // TCCR2B = Timer/Counter 2 Control Register B containing: FOC2A FOC2B – – WGM22 CS22 CS21 CS20
        // FOC2A: Force Output Compare A. The FOC2A bit is only active when the WGM bits specify a non-PWM mode
        // FOC2B: Force Output Compare B. The FOC2B bit is only active when the WGM bits specify a non-PWM mode.
        // CS22:0: Clock Select. The three Clock Select bits select the clock source to be used by the Timer/Counter
        // Clock Select = 011 = SYSKLOCK/32 at 20MHz / 32 = 625 kHz
        // The timer increments from 0x00 to OCR2A with an update rate of 625 kHz or 0.0016 ms
        //
        TCCR2B &= ~((1<<FOC2A)|(1<<FOC2B)|(1<<CS22));
        TCCR2B |= (1<<CS21)|(1<<CS20)|(1<<WGM22);
       
        //------------------------------------------------------------------------------------------
        // Reset the Timer/Counter 2
        TCNT2 = 0;
       
        OCR2A = 255;                                                    // Initialize the Output Compare Register A used for PWM generation on port PD7.
        TCCR2A |= (1<<COM2A1);                          // Clear OC2A on Compare Match when up-counting. Set OC2A on Compare Match when down-counting
       
        //------------------------------------------------------------------------------------------
        // TIMSK2 – Timer/Counter2 Interrupt Mask Register containing: – – – – – OCIE2B OCIE2A TOIE2
        // OCIE2B: Timer/Counter2 Output Compare Match B Interrupt Enable
        // TOIE2: Timer/Counter2 Overflow Interrupt Enable
        //
        TIMSK2 &= ~((1<<OCIE2B)|(1<<TOIE2));    // Output Compare Match B Interrupt is dissabled as Overflow Interrupt
        TIMSK2 |= (1<<OCIE2A);                                  // Timer/Counter2 Output Compare Match A Interrupt is enabled
       
        SREG = sreg;                                                    // recopy SREG – Status Register
}
// *************************************************************************************************************************



// *************************************************************************************************************************
// Timer2 controlls the  Position of Control Servos at
// OC2A=PORTD7
//---------------------------------------------------------------------------------------------------------------------------------------------
ISR(TIMER2_COMPA_vect)
{
        // frame len 22.5 ms = 14063 * 1.6 us
        // stop pulse: 0.3 ms = 188 * 1.6 us
        // min servo pulse: 0.6 ms =  375 * 1.6 us
        // max servo pulse: 2.4 ms = 1500 * 1.6 us
        // resolution: 1500 - 375 = 1125 steps
       
        #define IRS_RUNTIME 127
        #define PPM_STOPPULSE 188
    #define PPM_FRAMELEN (1757 * EE_Parameter.ServoNickRefresh)
        #define MINSERVOPULSE 375
        #define MAXSERVOPULSE 1500
        #define SERVORANGE (MAXSERVOPULSE - MINSERVOPULSE)
       
        static uint8_t  PulseOutput = 0;
        static uint16_t RemainingPulse = 0;
        static uint16_t ServoFrameTime = 0;
        //static uint8_t  ServoIndex = 0;
       
        #define MULTIPLYER 4
        static int16_t ServoNickOffset = (255 / 2) * MULTIPLYER;        // initial value near center positon
        //static int16_t ServoRollOffset = (255 / 2) * MULTIPLYER;      // initial value near center positon
       
        //------------------------------------------------------------------------------------------------------------------------
        // Nick servo state machine
        //------------------------------------------------------------------------------------------------------------------------
        if(!PulseOutput) // pulse output complete
        {
                if(TCCR2A & (1<<COM2A0))                                                                        // we had a low pulse
                {
                        TCCR2A &= ~(1<<COM2A0);                                                         // make a high pulse
                        RemainingPulse  = MINSERVOPULSE + SERVORANGE/2;                 // center position ~ 1.5ms
                       
                        ServoNickOffset = (ServoNickOffset * 3 + (int16_t)Parameter_ServoNickControl * MULTIPLYER) / 4; // lowpass offset
                        ServoNickValue = ServoNickOffset;                                               // offset (Range from 0 to 255 * 3 = 765)
                       
                        if(EE_Parameter.ServoCompInvert & 0x01)
                        {       // inverting movement of servo
                                ServoNickValue += (int16_t)( ( (int32_t)EE_Parameter.ServoNickComp * MULTIPLYER * (IntegralNick / 128L ) ) / (256L) );
                        }
                        else
                        {       // non inverting movement of servo
                                ServoNickValue -= (int16_t)( ( (int32_t)EE_Parameter.ServoNickComp * MULTIPLYER * (IntegralNick / 128L ) ) / (256L) );
                        }
                       
                        // limit servo value to its parameter range definition
                        if(ServoNickValue < ((int16_t)EE_Parameter.ServoNickMin * MULTIPLYER) )
                        {
                                ServoNickValue = (int16_t)EE_Parameter.ServoNickMin * MULTIPLYER;
                        }
                        else if(ServoNickValue > ((int16_t)EE_Parameter.ServoNickMax * MULTIPLYER) )
                        {
                                ServoNickValue = (int16_t)EE_Parameter.ServoNickMax * MULTIPLYER;
                        }
                       
                        RemainingPulse += ServoNickValue - (256 / 2) * MULTIPLYER; // shift ServoNickValue to center position
                       
                        ServoNickValue /= MULTIPLYER;
                       
                        // range servo pulse width
                        if(RemainingPulse > MAXSERVOPULSE )                     RemainingPulse = MAXSERVOPULSE; // upper servo pulse limit
                        else if(RemainingPulse < MINSERVOPULSE )        RemainingPulse = MINSERVOPULSE; // lower servo pulse limit
                       
                        ServoFrameTime = RemainingPulse;                                        // accumulate time for correct update rate
                }
                else                                                                                                    // we had a high pulse
                {
                        TCCR2A |= (1<<COM2A0);                                                  // make a low pulse
                        RemainingPulse = PPM_FRAMELEN - ServoFrameTime;
                }
                PulseOutput = 1;                                                                                // set pulse output active
        }

        if(RemainingPulse > (255 + IRS_RUNTIME))                                        // General pulse output generator
        {
                OCR2A = 255;
                RemainingPulse -= 255;
        }
        else
        {
                if(RemainingPulse > 255)                                                                // this is the 2nd last part
                {
                        if((RemainingPulse - 255) < IRS_RUNTIME)
                        {
                                OCR2A = 255 - IRS_RUNTIME;
                                RemainingPulse -= 255 - IRS_RUNTIME;
                        }
                        else                                                                                            // last part > ISR_RUNTIME
                        {
                                OCR2A = 255;
                                RemainingPulse -= 255;
                        }
                }
                else                                                                                                    // this is the last part
                {
                        OCR2A = RemainingPulse;
                        RemainingPulse = 0;
                        PulseOutput = 0;                                                                        // trigger to stop pulse
                }
               
        } // EOF: general pulse output generator       
}
// *** EOF: ISR(TIMER2_COMPA_vect) ***************************************************************************************