Subversion Repositories FlightCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 ingob 1
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2
// + Copyright (c) 04.2007 Holger Buss
1180 killagreg 3
// + Nur für den privaten Gebrauch
1 ingob 4
// + www.MikroKopter.com
5
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1180 killagreg 6
// + Es gilt für das gesamte Projekt (Hardware, Software, Binärfiles, Sourcecode und Dokumentation),
7
// + dass eine Nutzung (auch auszugsweise) nur für den privaten (nicht-kommerziellen) Gebrauch zulässig ist.
8
// + Sollten direkte oder indirekte kommerzielle Absichten verfolgt werden, ist mit uns (info@mikrokopter.de) Kontakt
9
// + bzgl. der Nutzungsbedingungen aufzunehmen.
10
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen,
11
// + Verkauf von Luftbildaufnahmen, usw.
12
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13
// + Werden Teile des Quellcodes (mit oder ohne Modifikation) weiterverwendet oder veröffentlicht,
14
// + unterliegen sie auch diesen Nutzungsbedingungen und diese Nutzungsbedingungen incl. Copyright müssen dann beiliegen
15
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16
// + Sollte die Software (auch auszugesweise) oder sonstige Informationen des MikroKopter-Projekts
17
// + auf anderen Webseiten oder sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
18
// + eindeutig als Ursprung verlinkt werden
19
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion
21
// + Benutzung auf eigene Gefahr
22
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden
23
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24
// + Die Portierung der Software (oder Teile davon) auf andere Systeme (ausser der Hardware von www.mikrokopter.de) ist nur
25
// + mit unserer Zustimmung zulässig
26
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
27
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen
28
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
29
// + Redistributions of source code (with or without modifications) must retain the above copyright notice,
30
// + this list of conditions and the following disclaimer.
31
// +   * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived
32
// +     from this software without specific prior written permission.
33
// +   * The use of this project (hardware, software, binary files, sources and documentation) is only permittet
34
// +     for non-commercial use (directly or indirectly)
35
// +     Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
36
// +     with our written permission
37
// +   * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be
38
// +     clearly linked as origin
39
// +   * porting to systems other than hardware from www.mikrokopter.de is not allowed
40
// +  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41
// +  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
// +  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
// +  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
44
// +  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45
// +  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46
// +  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47
// +  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN// +  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48
// +  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49
// +  POSSIBILITY OF SUCH DAMAGE.
50
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
886 killagreg 51
#include <stdlib.h>
52
#include <avr/io.h>
53
#include <avr/interrupt.h>
1 ingob 54
 
886 killagreg 55
#include "analog.h"
1 ingob 56
#include "main.h"
886 killagreg 57
#include "timer0.h"
58
#include "fc.h"
59
#include "printf_P.h"
60
#include "eeprom.h"
936 killagreg 61
#include "twimaster.h"
1 ingob 62
 
1180 killagreg 63
volatile uint16_t Test = 0;
64
 
886 killagreg 65
volatile int16_t UBat = 100;
1180 killagreg 66
volatile int16_t AdValueGyroNick = 0, AdValueGyroRoll = 0,  AdValueGyroYaw = 0;
67
volatile int16_t FilterHiResGyroNick = 0, FilterHiResGyroRoll = 0;
68
volatile int16_t HiResGyroNick = 2500, HiResGyroRoll = 2500;
69
volatile int16_t AdValueAccRoll = 0,  AdValueAccNick = 0, AdValueAccTop = 0, AdValueAccZ = 0;
886 killagreg 70
volatile int32_t AirPressure = 32000;
936 killagreg 71
volatile uint8_t average_pressure = 0;
886 killagreg 72
volatile int16_t StartAirPressure;
73
volatile uint16_t ReadingAirPressure = 1023;
74
volatile int16_t HeightD = 0;
75
volatile uint16_t MeasurementCounter = 0;
1180 killagreg 76
volatile uint8_t ADReady = 1;
1 ingob 77
 
1180 killagreg 78
uint8_t DacOffsetGyroNick = 115, DacOffsetGyroRoll = 115, DacOffsetGyroYaw = 115;
79
uint8_t GyroDefectNick = 0, GyroDefectRoll = 0, GyroDefectYaw = 0;
80
int8_t ExpandBaro = 0;
81
uint8_t PressureSensorOffset;
82
 
886 killagreg 83
/*****************************************************/
84
/*     Initialize Analog Digital Converter           */
85
/*****************************************************/
1 ingob 86
void ADC_Init(void)
886 killagreg 87
{
88
        uint8_t sreg = SREG;
89
        // disable all interrupts before reconfiguration
90
        cli();
91
        //ADC0 ... ADC7 is connected to PortA pin 0 ... 7
92
        DDRA = 0x00;
93
        PORTA = 0x00;
94
        // Digital Input Disable Register 0
95
        // Disable digital input buffer for analog adc_channel pins
96
        DIDR0 = 0xFF;
97
        // external reference, adjust data to the right
98
    ADMUX &= ~((1 << REFS1)|(1 << REFS0)|(1 << ADLAR));
99
    // set muxer to ADC adc_channel 0 (0 to 7 is a valid choice)
100
    ADMUX = (ADMUX & 0xE0) | 0x00;
101
    //Set ADC Control and Status Register A
102
    //Auto Trigger Enable, Prescaler Select Bits to Division Factor 128, i.e. ADC clock = SYSCKL/128 = 156.25 kHz
1180 killagreg 103
        ADCSRA = (0<<ADEN)|(0<<ADSC)|(0<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(0<<ADIE);
886 killagreg 104
        //Set ADC Control and Status Register B
105
        //Trigger Source to Free Running Mode
106
        ADCSRB &= ~((1 << ADTS2)|(1 << ADTS1)|(1 << ADTS0));
1180 killagreg 107
        // Start AD conversion
886 killagreg 108
        ADC_Enable();
109
    // restore global interrupt flags
110
    SREG = sreg;
1 ingob 111
}
112
 
886 killagreg 113
void SearchAirPressureOffset(void)
1 ingob 114
{
886 killagreg 115
        uint8_t off;
116
        off = GetParamByte(PID_PRESSURE_OFFSET);
117
        if(off > 20) off -= 10;
118
        OCR0A = off;
1078 killagreg 119
        ExpandBaro = 0;
886 killagreg 120
        Delay_ms_Mess(100);
121
        if(ReadingAirPressure < 850) off = 0;
122
        for(; off < 250;off++)
123
        {
124
                OCR0A = off;
125
                Delay_ms_Mess(50);
126
                printf(".");
1078 killagreg 127
                if(ReadingAirPressure < 850) break;
886 killagreg 128
        }
129
        SetParamByte(PID_PRESSURE_OFFSET, off);
130
        PressureSensorOffset = off;
131
        Delay_ms_Mess(300);
1 ingob 132
}
133
 
134
 
1180 killagreg 135
void SearchDacGyroOffset(void)
936 killagreg 136
{
137
        uint8_t i, ready = 0;
138
 
139
        GyroDefectNick = 0; GyroDefectRoll = 0; GyroDefectYaw = 0;
1180 killagreg 140
        if(BoardRelease == 13) // the auto offset calibration is available only at board release 1.3
141
        {
142
                for(i = 140; i != 0; i--)
143
                {
144
                        if(ready == 3 && i > 10) i = 9;
145
                        ready = 0;
146
                        if(AdValueGyroNick < 1020) DacOffsetGyroNick--; else if(AdValueGyroNick > 1030) DacOffsetGyroNick++; else ready++;
147
                        if(AdValueGyroRoll < 1020) DacOffsetGyroRoll--; else if(AdValueGyroRoll > 1030) DacOffsetGyroRoll++; else ready++;
148
                        if(AdValueGyroYaw  < 1020) DacOffsetGyroYaw-- ; else if(AdValueGyroYaw  > 1030) DacOffsetGyroYaw++ ; else ready++;
149
                        twi_state = TWI_STATE_GYRO_OFFSET_TX; // set twi_state in TWI ISR to start of Gyro Offset
150
                        I2C_Start();   // initiate data transmission
151
                        if(DacOffsetGyroNick < 10)  { GyroDefectNick = 1; DacOffsetGyroNick = 10;}; if(DacOffsetGyroNick > 245) { GyroDefectNick = 1; DacOffsetGyroNick = 245;};
152
                        if(DacOffsetGyroRoll < 10)  { GyroDefectRoll = 1; DacOffsetGyroRoll = 10;}; if(DacOffsetGyroRoll > 245) { GyroDefectRoll = 1; DacOffsetGyroRoll = 245;};
153
                        if(DacOffsetGyroYaw  < 10)  { GyroDefectYaw  = 1; DacOffsetGyroYaw  = 10;}; if(DacOffsetGyroYaw  > 245) { GyroDefectYaw  = 1; DacOffsetGyroYaw  = 245;};
154
                        while(twi_state); // wait for end of data transmission
155
                        average_pressure = 0;
156
                        ADC_Enable();
157
                        while(average_pressure == 0);
158
                        if(i < 10) Delay_ms_Mess(10);
159
                }
160
                Delay_ms_Mess(70);
936 killagreg 161
        }
162
}
163
 
164
 
165
 
166
 
886 killagreg 167
/*****************************************************/
168
/*     Interrupt Service Routine for ADC             */
169
/*****************************************************/
1180 killagreg 170
// runs at 312.5 kHz or 3.2 µs
171
// if after (60.8µs) all 19 states are processed the interrupt is disabled
886 killagreg 172
// and the update of further ads is stopped
173
 
1180 killagreg 174
/*
175
 
176
1  rollgyro
177
2  yawgyro
178
3  accroll
179
4  accnick
180
5  nickgyro
181
6  rollgyro
182
7  ubat
183
8  acctop
184
9  air pressure
185
10 nickgyro
186
11 rollgyro
187
12 yawgyro
188
13 accroll
189
14 accnick
190
15 gyronick
191
16 gyroroll
192
17 airpressure
193
*/
194
 
195
 
196
#define AD_GYRO_YAW             0
197
#define AD_GYRO_ROLL    1
198
#define AD_GYRO_NICK    2
199
#define AD_AIRPRESS             3
200
#define AD_UBAT                 4
201
#define AD_ACC_TOP              5
202
#define AD_ACC_ROLL             6
203
#define AD_ACC_NICK             7
204
 
886 killagreg 205
ISR(ADC_vect)
1 ingob 206
{
1180 killagreg 207
    static uint8_t ad_channel = AD_GYRO_NICK, state = 0;
208
    static uint16_t gyroyaw, gyroroll, gyronick, accroll, accnick;
209
    static int32_t filtergyronick, filtergyroroll;
886 killagreg 210
    static int16_t tmpAirPressure = 0;
1180 killagreg 211
 
886 killagreg 212
    // state machine
1180 killagreg 213
        switch(state++)
214
        {
215
                case 0:
216
                        gyronick = ADC; // get nick gyro voltage 1st sample
217
                        ad_channel = AD_GYRO_ROLL;
218
                        break;
219
                case 1:
220
                        gyroroll = ADC; // get roll gyro voltage 1st sample
221
                        ad_channel = AD_GYRO_YAW;
222
                        break;
223
                case 2:
224
                        gyroyaw = ADC; // get yaw gyro voltage 1st sample
225
                        ad_channel = AD_ACC_ROLL;
226
                        break;
227
                case 3:
228
                        accroll = ADC; // get roll acc voltage 1st sample
229
                        ad_channel = AD_ACC_NICK;
1 ingob 230
            break;
1180 killagreg 231
                case 4:
232
                        accnick = ADC; // get nick acc voltage 1st sample
233
                        ad_channel = AD_GYRO_NICK;
234
                        break;
235
                case 5:
236
                        gyronick += ADC; // get nick gyro voltage 2nd sample
237
                        ad_channel = AD_GYRO_ROLL;
238
                        break;
239
                case 6:
240
                        gyroroll += ADC; // get roll gyro voltage 2nd sample
241
                        ad_channel = AD_UBAT;
242
                        break;
243
                case 7:
244
                        // get actual UBat (Volts*10) is ADC*30V/1024*10 = ADC/3
245
                        UBat = (3 * UBat + ADC / 3) / 4; // low pass filter updates UBat only to 1 quater with actual ADC value
246
                        ad_channel = AD_ACC_TOP;
1 ingob 247
            break;
1180 killagreg 248
                case 8:
249
                        AdValueAccZ = ADC; // get plain acceleration in Z direction
250
                        AdValueAccTop =  (int16_t)ADC - AdBiasAccTop; // get acceleration in Z direction
251
                        if(AdValueAccTop > 1)
252
                        {
253
                                if(AdBiasAccTop < 750)
254
                                {
255
                                        AdBiasAccTop += 0.02;
256
                                        if(ModelIsFlying < 500) AdBiasAccTop += 0.1;
886 killagreg 257
                                }
1180 killagreg 258
                        }
259
                        else if(AdValueAccTop < -1)
260
                        {
261
                                if(AdBiasAccTop > 550)
262
                                {
263
                                        AdBiasAccTop -= 0.02;
264
                                        if(ModelIsFlying < 500) AdBiasAccTop -= 0.1;
886 killagreg 265
                                }
1180 killagreg 266
                        }
267
                        ReadingIntegralTop += AdValueAccTop;      // load
268
                        ReadingIntegralTop -= ReadingIntegralTop / 1024; // discharge
269
                        ad_channel = AD_AIRPRESS;
270
                        break;
271
                // case 9 is moved to the end
272
                case 10:
273
                        gyronick += ADC; // get nick gyro voltage 3rd sample
274
                        ad_channel = AD_GYRO_ROLL;
275
                        break;
276
                case 11:
277
                        gyroroll += ADC; // get roll gyro voltage 3rd sample
278
                        ad_channel = AD_GYRO_YAW;
279
                        break;
280
                case 12:
281
                        gyroyaw += ADC; // get yaw gyro voltage 2nd sample
282
                        if(BoardRelease == 10) AdValueGyroYaw = (gyroyaw + 1) / 2; // analog gain on board 1.0 is 2 times higher
283
                        else
284
                        if(BoardRelease == 20) AdValueGyroYaw = 2047 - gyroyaw; // 2 times higher than a single sample
285
                        else                   AdValueGyroYaw = gyroyaw;        // 2 times higher than a single sample
286
                        ad_channel = AD_ACC_ROLL;
287
                        break;
288
                case 13:
289
                        accroll += ADC; // get roll acc voltage 2nd sample
290
                        AdValueAccRoll = AdBiasAccRoll - accroll; // subtract bias
291
                        ad_channel = AD_ACC_NICK;
292
                        break;
293
                case 14:
294
                        accnick += ADC; // get nick acc voltage 2nd sample
295
                        AdValueAccNick = accnick  - AdBiasAccNick; // subtract bias
296
                        ad_channel = AD_GYRO_NICK;
1 ingob 297
            break;
1180 killagreg 298
        case 15:
299
                gyronick += ADC; // get nick gyro voltage 4th sample
300
                if(BoardRelease == 10) gyronick *= 2; // 8 times higer than a single sample, HW gain x2
301
                else gyronick *= 4; // 16 times higer than a single sample
302
                        AdValueGyroNick = gyronick / 8; // 2 times higher than a single sample
303
                        filtergyronick = (filtergyronick + gyronick) / 2; //(16 samples)/2 results in a factor of 8 higher than a single sample) see HIRES_GYRO_AMPLIFY
304
                        HiResGyroNick = filtergyronick - BiasHiResGyroNick;
305
                        FilterHiResGyroNick = (FilterHiResGyroNick + HiResGyroNick) / 2;
306
                        ad_channel = AD_GYRO_ROLL;
307
                        break;
308
        case 16:
309
                gyroroll += ADC; // get roll gyro voltage 4th sample
310
                if(BoardRelease == 10) gyroroll *= 2; // 8 times higer than a single sample, HW gain x2
311
                else gyroroll *= 4; // 16 times higer than a single sample
312
                        AdValueGyroRoll = gyroroll / 8; // 2 times higher than a single sample
313
                        filtergyroroll = (filtergyroroll + gyroroll) / 2; //(16 samples)/2 results in a factor of 8 higher than a single sample) see HIRES_GYRO_AMPLIFY
314
                        HiResGyroRoll = filtergyroroll - BiasHiResGyroRoll;
315
                        FilterHiResGyroRoll = (FilterHiResGyroRoll + HiResGyroRoll) / 2;
316
                        ad_channel = AD_AIRPRESS;
317
                        break;
318
                case 17:
319
                        state = 0; // restart sequence from beginning
320
            ADReady = 1; // mark
321
            MeasurementCounter++; // increment total measurement counter
322
                        // "break;" is missing to enable fall thru case 9 at the end of the sequence
323
                case 9:
324
                        tmpAirPressure += ADC; // sum adc values
325
                        if(++average_pressure >= 5) // if 5 values are summerized for averaging
326
                        {
327
                                tmpAirPressure /= 2;
328
                                ReadingAirPressure = ADC; // update meassured air pressure
329
                                HeightD = (31 * HeightD + (int16_t)FCParam.HeightD * (int16_t)(255 * ExpandBaro + StartAirPressure - tmpAirPressure - ReadingHeight)) / 32;  // D-Part = CurrentValue - OldValue
330
                                AirPressure = (tmpAirPressure + 7 * AirPressure + 4) / 8; // averaging using history
331
                                ReadingHeight = 255 * ExpandBaro + StartAirPressure - AirPressure;
332
                                average_pressure = 0; // reset air pressure measurement counter
333
                                tmpAirPressure /= 2;
334
                        }
335
                        ad_channel = AD_GYRO_NICK;
336
                        break;
337
                default:
338
                        ad_channel = AD_GYRO_NICK;
339
                        state = 0;
340
                        break;
341
        }
342
    // set adc muxer to next ad_channel
343
    ADMUX = (ADMUX & 0xE0) | ad_channel;
886 killagreg 344
    // after full cycle stop further interrupts
345
    if(state != 0) ADC_Enable();
1 ingob 346
}