Subversion Repositories FlightCtrl

Rev

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

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Copyright (c) Holger Buss, Ingo Busker
// + Nur für den privaten Gebrauch
// + www.MikroKopter.com
// + porting the sources to other systems or using the software on other systems (except hardware from www.mikrokopter.de) is not allowed
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Es gilt für das gesamte Projekt (Hardware, Software, Binärfiles, Sourcecode und Dokumentation),
// + dass eine Nutzung (auch auszugsweise) nur für den privaten (nicht-kommerziellen) Gebrauch zulässig ist.
// + Sollten direkte oder indirekte kommerzielle Absichten verfolgt werden, ist mit uns (info@mikrokopter.de) Kontakt
// + bzgl. der Nutzungsbedingungen aufzunehmen.
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen,
// + Verkauf von Luftbildaufnahmen, usw.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Werden Teile des Quellcodes (mit oder ohne Modifikation) weiterverwendet oder veröffentlicht,
// + unterliegen sie auch diesen Nutzungsbedingungen und diese Nutzungsbedingungen incl. Copyright müssen dann beiliegen
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Sollte die Software (auch auszugesweise) oder sonstige Informationen des MikroKopter-Projekts
// + auf anderen Webseiten oder sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
// + eindeutig als Ursprung verlinkt werden
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion
// + Benutzung auf eigene Gefahr
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Die Portierung der Software (oder Teile davon) auf andere Systeme (ausser der Hardware von www.mikrokopter.de) ist nur
// + mit unserer Zustimmung zulässig
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Redistributions of source code (with or without modifications) must retain the above copyright notice,
// + this list of conditions and the following disclaimer.
// +   * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived
// +     from this software without specific prior written permission.
// +   * The use of this project (hardware, software, binary files, sources and documentation) is only permittet
// +     for non-commercial use (directly or indirectly)
// +     Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
// +     with our written permission
// +   * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be
// +     clearly linked as origin
// +   * porting to systems other than hardware from www.mikrokopter.de is not allowed
// +  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// +  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// +  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// +  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// +  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// +  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// +  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// +  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN// +  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// +  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// +  POSSIBILITY OF SUCH DAMAGE.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#include "analog.h"
#include "main.h"
#include "timer0.h"
#include "fc.h"
#include "printf_P.h"
#include "eeprom.h"
#include "twimaster.h"
#include "uart0.h"

volatile uint16_t Test = 0;

volatile int16_t UBat = 100;
volatile int16_t AdValueGyroNick = 0, AdValueGyroRoll = 0,  AdValueGyroYaw = 0;
volatile int16_t FilterHiResGyroNick = 0, FilterHiResGyroRoll = 0;
volatile int16_t HiResGyroNick = 2500, HiResGyroRoll = 2500;
volatile int16_t AdValueAccRoll = 0,  AdValueAccNick = 0, AdValueAccTop = 0, AdValueAccZ = 0;
volatile int32_t AirPressure = 32000;
volatile int32_t StartAirPressure;
volatile int16_t AdAirPressure = 1023;
volatile int32_t ReadingHeight = 0;
volatile int16_t ReadingVario = 0;
volatile int32_t SumHeight = 0;
volatile uint16_t MeasurementCounter = 0;
volatile uint8_t ADReady = 1;

uint8_t DacOffsetGyroNick = 115, DacOffsetGyroRoll = 115, DacOffsetGyroYaw = 115;
uint8_t GyroDefectNick = 0, GyroDefectRoll = 0, GyroDefectYaw = 0;
int8_t ExpandBaro = 0;
uint8_t PressureSensorOffset;

/*****************************************************/
/*     Initialize Analog Digital Converter           */
/*****************************************************/
void ADC_Init(void)
{
        uint8_t sreg = SREG;
        // disable all interrupts before reconfiguration
        cli();
        //ADC0 ... ADC7 is connected to PortA pin 0 ... 7
        DDRA = 0x00;
        PORTA = 0x00;
        // Digital Input Disable Register 0
        // Disable digital input buffer for analog adc_channel pins
        DIDR0 = 0xFF;
        // external reference, adjust data to the right
    ADMUX &= ~((1 << REFS1)|(1 << REFS0)|(1 << ADLAR));
    // set muxer to ADC adc_channel 0 (0 to 7 is a valid choice)
    ADMUX = (ADMUX & 0xE0) | 0x00;
    //Set ADC Control and Status Register A
    //Auto Trigger Enable, Prescaler Select Bits to Division Factor 128, i.e. ADC clock = SYSCKL/128 = 156.25 kHz
        ADCSRA = (0<<ADEN)|(0<<ADSC)|(0<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(0<<ADIE);
        //Set ADC Control and Status Register B
        //Trigger Source to Free Running Mode
        ADCSRB &= ~((1 << ADTS2)|(1 << ADTS1)|(1 << ADTS0));
        // Start AD conversion
        ADC_Enable();
    // restore global interrupt flags
    SREG = sreg;
}

void SearchAirPressureOffset(void)
{
        uint8_t off;
        off = GetParamByte(PID_PRESSURE_OFFSET);
        if(off > 20) off -= 10;
        OCR0A = off;
        ExpandBaro = 0;
        Delay_ms_Mess(100);
        if(AdAirPressure < AIR_PRESSURE_SEARCH) off = 0;
        for(; off < 250;off++)
        {
                OCR0A = off;
                Delay_ms_Mess(50);
                printf(".");
                if(AdAirPressure < AIR_PRESSURE_SEARCH) break;
        }
        SetParamByte(PID_PRESSURE_OFFSET, off);
        PressureSensorOffset = off;
        AirPressure = AIR_PRESSURE_SCALE * (int32_t)AdAirPressure; // init IIR Filter
        Delay_ms_Mess(300);
}


void SearchDacGyroOffset(void)
{
        uint8_t i, ready = 0;
        uint16_t timeout ;

        GyroDefectNick = 0; GyroDefectRoll = 0; GyroDefectYaw = 0;

        timeout = SetDelay(2000);
        if(BoardRelease == 13) // the auto offset calibration is available only at board release 1.3
        {
                for(i = 140; i != 0; i--)
                {
                        if(ready == 3 && i > 10) i = 9;
                        ready = 0;
                        if(AdValueGyroNick < 1020) DacOffsetGyroNick--; else if(AdValueGyroNick > 1030) DacOffsetGyroNick++; else ready++;
                        if(AdValueGyroRoll < 1020) DacOffsetGyroRoll--; else if(AdValueGyroRoll > 1030) DacOffsetGyroRoll++; else ready++;
                        if(AdValueGyroYaw  < 1020) DacOffsetGyroYaw-- ; else if(AdValueGyroYaw  > 1030) DacOffsetGyroYaw++ ; else ready++;
                        I2C_Start(TWI_STATE_GYRO_OFFSET_TX);   // initiate data transmission
                        if(DacOffsetGyroNick < 10)  { GyroDefectNick = 1; DacOffsetGyroNick = 10;}; if(DacOffsetGyroNick > 245) { GyroDefectNick = 1; DacOffsetGyroNick = 245;};
                        if(DacOffsetGyroRoll < 10)  { GyroDefectRoll = 1; DacOffsetGyroRoll = 10;}; if(DacOffsetGyroRoll > 245) { GyroDefectRoll = 1; DacOffsetGyroRoll = 245;};
                        if(DacOffsetGyroYaw  < 10)  { GyroDefectYaw  = 1; DacOffsetGyroYaw  = 10;}; if(DacOffsetGyroYaw  > 245) { GyroDefectYaw  = 1; DacOffsetGyroYaw  = 245;};
                        while(twi_state)
                        {
                                if(CheckDelay(timeout))
                                {
                                        printf("\r\n DAC or I2C Error1 check I2C, 3Vref, DAC, and BL-Ctrl");
                                        break;
                                }
                        } // wait for end of data transmission
                        ADReady = 0;
                        ADC_Enable();
                        while(!ADReady);
                        if(i < 10) Delay_ms_Mess(10);
                }
                Delay_ms_Mess(70);
        }
}




/*****************************************************/
/*     Interrupt Service Routine for ADC             */
/*****************************************************/
// runs at 312.5 kHz or 3.2 µs
// if after (60.8µs) all 19 states are processed the interrupt is disabled
// and the update of further ads is stopped

/*
0  nickgyro
1  rollgyro
2  yawgyro
3  accroll
4  accnick
5  nickgyro
6  rollgyro
7  ubat
8  acctop
9  air pressure
10 nickgyro
11 rollgyro
12 yawgyro
13 accroll
14 accnick
15 gyronick
16 gyroroll
17 air pressure
*/



#define AD_GYRO_YAW             0
#define AD_GYRO_ROLL    1
#define AD_GYRO_NICK    2
#define AD_AIRPRESS             3
#define AD_UBAT                 4
#define AD_ACC_TOP              5
#define AD_ACC_ROLL             6
#define AD_ACC_NICK             7

ISR(ADC_vect)
{
    static uint8_t ad_channel = AD_GYRO_NICK, state = 0;
    static uint16_t gyroyaw, gyroroll, gyronick, accroll, accnick;
    static int32_t filtergyronick, filtergyroroll;
    static int32_t tmpAirPressure = 0;
    static uint8_t AirPressCount = 0;

    // state machine
        switch(state++)
        {
                case 0:
                        gyronick = ADC; // get nick gyro voltage 1st sample
                        ad_channel = AD_GYRO_ROLL;
                        break;
                case 1:
                        gyroroll = ADC; // get roll gyro voltage 1st sample
                        ad_channel = AD_GYRO_YAW;
                        break;
                case 2:
                        gyroyaw = ADC; // get yaw gyro voltage 1st sample
                        ad_channel = AD_ACC_ROLL;
                        break;
                case 3:
                        accroll = ADC; // get roll acc voltage 1st sample
                        ad_channel = AD_ACC_NICK;
            break;
                case 4:
                        accnick = ADC; // get nick acc voltage 1st sample
                        ad_channel = AD_GYRO_NICK;
                        break;
                case 5:
                        gyronick += ADC; // get nick gyro voltage 2nd sample
                        ad_channel = AD_GYRO_ROLL;
                        break;
                case 6:
                        gyroroll += ADC; // get roll gyro voltage 2nd sample
                        ad_channel = AD_UBAT;
                        break;
                case 7:
                        // get actual UBat (Volts*10) is ADC*30V/1024*10 = ADC/3
                        UBat = (3 * UBat + ADC / 3) / 4; // low pass filter updates UBat only to 1 quater with actual ADC value
                        ad_channel = AD_ACC_TOP;
            break;
                case 8:
                        AdValueAccZ = ADC; // get plain acceleration in Z direction
                        AdValueAccTop =  (int16_t)ADC - AdBiasAccTop; // get acceleration in Z direction
                        if(AdValueAccTop > 1)
                        {
                                if(AdBiasAccTop < 750)
                                {
                                        AdBiasAccTop += 0.02;
                                        if(ModelIsFlying < 500) AdBiasAccTop += 0.1;
                                }
                        }
                        else if(AdValueAccTop < -1)
                        {
                                if(AdBiasAccTop > 550)
                                {
                                        AdBiasAccTop -= 0.02;
                                        if(ModelIsFlying < 500) AdBiasAccTop -= 0.1;
                                }
                        }
                        // averaging acc
                        ReadingIntegralTop -= ReadingIntegralTop / 1024; // discharge
                        ReadingIntegralTop += AdValueAccTop; // load
                        ad_channel = AD_AIRPRESS;
                        break;
                // case 9 is moved to the end
                case 10:
                        gyronick += ADC; // get nick gyro voltage 3rd sample
                        ad_channel = AD_GYRO_ROLL;
                        break;
                case 11:
                        gyroroll += ADC; // get roll gyro voltage 3rd sample
                        ad_channel = AD_GYRO_YAW;
                        break;
                case 12:
                        gyroyaw += ADC; // get yaw gyro voltage 2nd sample
                        if(BoardRelease == 10) AdValueGyroYaw = (gyroyaw + 1) / 2; // analog gain on board 1.0 is 2 times higher
                        else
                        if(BoardRelease == 20) AdValueGyroYaw = 2047 - gyroyaw; // 2 times higher than a single sample
                        else                   AdValueGyroYaw = gyroyaw;        // 2 times higher than a single sample
                        ad_channel = AD_ACC_ROLL;
                        break;
                case 13:
                        accroll += ADC; // get roll acc voltage 2nd sample
                        AdValueAccRoll = AdBiasAccRoll - accroll; // subtract bias
                        ad_channel = AD_ACC_NICK;
                        break;
                case 14:
                        accnick += ADC; // get nick acc voltage 2nd sample
                        AdValueAccNick = accnick  - AdBiasAccNick; // subtract bias
                        ad_channel = AD_GYRO_NICK;
            break;
        case 15:
                gyronick += ADC; // get nick gyro voltage 4th sample
                if(BoardRelease == 10) gyronick *= 2; // 8 times higer than a single sample, HW gain x2
                else gyronick *= 4; // 16 times higer than a single sample
                        AdValueGyroNick = gyronick / 8; // 2 times higher than a single sample
                        filtergyronick = (filtergyronick + gyronick) / 2; //(16 samples)/2 results in a factor of 8 higher than a single sample) see HIRES_GYRO_AMPLIFY
                        HiResGyroNick = filtergyronick - BiasHiResGyroNick;
                        FilterHiResGyroNick = (FilterHiResGyroNick + HiResGyroNick) / 2;
                        ad_channel = AD_GYRO_ROLL;
                        break;
        case 16:
                gyroroll += ADC; // get roll gyro voltage 4th sample
                if(BoardRelease == 10) gyroroll *= 2; // 8 times higer than a single sample, HW gain x2
                else gyroroll *= 4; // 16 times higher than a single sample
                        AdValueGyroRoll = gyroroll / 8; // 2 times higher than a single sample
                        filtergyroroll = (filtergyroroll + gyroroll) / 2; //(16 samples)/2 results in a factor of 8 higher than a single sample) see HIRES_GYRO_AMPLIFY
                        HiResGyroRoll = filtergyroroll - BiasHiResGyroRoll;
                        FilterHiResGyroRoll = (FilterHiResGyroRoll + HiResGyroRoll) / 2;
                        ad_channel = AD_AIRPRESS;
                        break;
                case 17:
                        state = 0; // restart sequence from beginning
            ADReady = 1; // mark
            MeasurementCounter++; // increment total measurement counter
                        // "break;" is missing to enable fall thru case 9 at the end of the sequence
                case 9:
                        AdAirPressure = ADC; // update meassured air pressure, changes -523 counts per OPA_OFFSET_STEP
                        tmpAirPressure += AdAirPressure;
                        if(++AirPressCount >= AIR_PRESSURE_SCALE)
                        {
                                #define AIRPRESSURE_FILTER_TIME 8
                                AirPressure = (AirPressure * (AIRPRESSURE_FILTER_TIME - 1) + tmpAirPressure + (AIR_PRESSURE_SCALE * EXPANDBARO_ADC_SHIFT) * (int32_t)ExpandBaro + AIRPRESSURE_FILTER_TIME/2)/AIRPRESSURE_FILTER_TIME;
                                ReadingHeight = (StartAirPressure - AirPressure); // change of air pressure to ground
                                SumHeight -= SumHeight/SM_FILTER;
                                SumHeight += ReadingHeight;
                                ReadingVario = (15 * ReadingVario + 8 * (int16_t)(ReadingHeight - SumHeight/SM_FILTER))/16;
                                tmpAirPressure /= 2;
                                AirPressCount = AIR_PRESSURE_SCALE/2;
                        }
                        ad_channel = AD_GYRO_NICK;
                        break;
                default:
                        ad_channel = AD_GYRO_NICK;
                        state = 0;
                        break;
        }
    // set adc muxer to next ad_channel
    ADMUX = (ADMUX & 0xE0) | ad_channel;
    // after full cycle stop further interrupts
    if(state != 0) ADC_Enable();
}