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;
1222 killagreg 138
        uint16_t timeout ;
936 killagreg 139
 
140
        GyroDefectNick = 0; GyroDefectRoll = 0; GyroDefectYaw = 0;
1222 killagreg 141
 
142
        timeout = SetDelay(2000);
1180 killagreg 143
        if(BoardRelease == 13) // the auto offset calibration is available only at board release 1.3
144
        {
145
                for(i = 140; i != 0; i--)
146
                {
147
                        if(ready == 3 && i > 10) i = 9;
148
                        ready = 0;
149
                        if(AdValueGyroNick < 1020) DacOffsetGyroNick--; else if(AdValueGyroNick > 1030) DacOffsetGyroNick++; else ready++;
150
                        if(AdValueGyroRoll < 1020) DacOffsetGyroRoll--; else if(AdValueGyroRoll > 1030) DacOffsetGyroRoll++; else ready++;
151
                        if(AdValueGyroYaw  < 1020) DacOffsetGyroYaw-- ; else if(AdValueGyroYaw  > 1030) DacOffsetGyroYaw++ ; else ready++;
1222 killagreg 152
                        I2C_Start(TWI_STATE_GYRO_OFFSET_TX);   // initiate data transmission
1180 killagreg 153
                        if(DacOffsetGyroNick < 10)  { GyroDefectNick = 1; DacOffsetGyroNick = 10;}; if(DacOffsetGyroNick > 245) { GyroDefectNick = 1; DacOffsetGyroNick = 245;};
154
                        if(DacOffsetGyroRoll < 10)  { GyroDefectRoll = 1; DacOffsetGyroRoll = 10;}; if(DacOffsetGyroRoll > 245) { GyroDefectRoll = 1; DacOffsetGyroRoll = 245;};
155
                        if(DacOffsetGyroYaw  < 10)  { GyroDefectYaw  = 1; DacOffsetGyroYaw  = 10;}; if(DacOffsetGyroYaw  > 245) { GyroDefectYaw  = 1; DacOffsetGyroYaw  = 245;};
1222 killagreg 156
                        while(twi_state)
157
                        {
158
                                if(CheckDelay(timeout))
159
                                {
160
                                        printf("\r\n DAC or I2C Error1 check I2C, 3Vref, DAC, and BL-Ctrl");
161
                                        break;
162
                                }
163
                        } // wait for end of data transmission
1180 killagreg 164
                        average_pressure = 0;
165
                        ADC_Enable();
166
                        while(average_pressure == 0);
167
                        if(i < 10) Delay_ms_Mess(10);
168
                }
169
                Delay_ms_Mess(70);
936 killagreg 170
        }
171
}
172
 
173
 
174
 
175
 
886 killagreg 176
/*****************************************************/
177
/*     Interrupt Service Routine for ADC             */
178
/*****************************************************/
1180 killagreg 179
// runs at 312.5 kHz or 3.2 µs
180
// if after (60.8µs) all 19 states are processed the interrupt is disabled
886 killagreg 181
// and the update of further ads is stopped
182
 
1180 killagreg 183
/*
184
 
185
1  rollgyro
186
2  yawgyro
187
3  accroll
188
4  accnick
189
5  nickgyro
190
6  rollgyro
191
7  ubat
192
8  acctop
193
9  air pressure
194
10 nickgyro
195
11 rollgyro
196
12 yawgyro
197
13 accroll
198
14 accnick
199
15 gyronick
200
16 gyroroll
201
17 airpressure
202
*/
203
 
204
 
205
#define AD_GYRO_YAW             0
206
#define AD_GYRO_ROLL    1
207
#define AD_GYRO_NICK    2
208
#define AD_AIRPRESS             3
209
#define AD_UBAT                 4
210
#define AD_ACC_TOP              5
211
#define AD_ACC_ROLL             6
212
#define AD_ACC_NICK             7
213
 
886 killagreg 214
ISR(ADC_vect)
1 ingob 215
{
1180 killagreg 216
    static uint8_t ad_channel = AD_GYRO_NICK, state = 0;
217
    static uint16_t gyroyaw, gyroroll, gyronick, accroll, accnick;
218
    static int32_t filtergyronick, filtergyroroll;
886 killagreg 219
    static int16_t tmpAirPressure = 0;
1180 killagreg 220
 
886 killagreg 221
    // state machine
1180 killagreg 222
        switch(state++)
223
        {
224
                case 0:
225
                        gyronick = ADC; // get nick gyro voltage 1st sample
226
                        ad_channel = AD_GYRO_ROLL;
227
                        break;
228
                case 1:
229
                        gyroroll = ADC; // get roll gyro voltage 1st sample
230
                        ad_channel = AD_GYRO_YAW;
231
                        break;
232
                case 2:
233
                        gyroyaw = ADC; // get yaw gyro voltage 1st sample
234
                        ad_channel = AD_ACC_ROLL;
235
                        break;
236
                case 3:
237
                        accroll = ADC; // get roll acc voltage 1st sample
238
                        ad_channel = AD_ACC_NICK;
1 ingob 239
            break;
1180 killagreg 240
                case 4:
241
                        accnick = ADC; // get nick acc voltage 1st sample
242
                        ad_channel = AD_GYRO_NICK;
243
                        break;
244
                case 5:
245
                        gyronick += ADC; // get nick gyro voltage 2nd sample
246
                        ad_channel = AD_GYRO_ROLL;
247
                        break;
248
                case 6:
249
                        gyroroll += ADC; // get roll gyro voltage 2nd sample
250
                        ad_channel = AD_UBAT;
251
                        break;
252
                case 7:
253
                        // get actual UBat (Volts*10) is ADC*30V/1024*10 = ADC/3
254
                        UBat = (3 * UBat + ADC / 3) / 4; // low pass filter updates UBat only to 1 quater with actual ADC value
255
                        ad_channel = AD_ACC_TOP;
1 ingob 256
            break;
1180 killagreg 257
                case 8:
258
                        AdValueAccZ = ADC; // get plain acceleration in Z direction
259
                        AdValueAccTop =  (int16_t)ADC - AdBiasAccTop; // get acceleration in Z direction
260
                        if(AdValueAccTop > 1)
261
                        {
262
                                if(AdBiasAccTop < 750)
263
                                {
264
                                        AdBiasAccTop += 0.02;
265
                                        if(ModelIsFlying < 500) AdBiasAccTop += 0.1;
886 killagreg 266
                                }
1180 killagreg 267
                        }
268
                        else if(AdValueAccTop < -1)
269
                        {
270
                                if(AdBiasAccTop > 550)
271
                                {
272
                                        AdBiasAccTop -= 0.02;
273
                                        if(ModelIsFlying < 500) AdBiasAccTop -= 0.1;
886 killagreg 274
                                }
1180 killagreg 275
                        }
276
                        ReadingIntegralTop += AdValueAccTop;      // load
277
                        ReadingIntegralTop -= ReadingIntegralTop / 1024; // discharge
278
                        ad_channel = AD_AIRPRESS;
279
                        break;
280
                // case 9 is moved to the end
281
                case 10:
282
                        gyronick += ADC; // get nick gyro voltage 3rd sample
283
                        ad_channel = AD_GYRO_ROLL;
284
                        break;
285
                case 11:
286
                        gyroroll += ADC; // get roll gyro voltage 3rd sample
287
                        ad_channel = AD_GYRO_YAW;
288
                        break;
289
                case 12:
290
                        gyroyaw += ADC; // get yaw gyro voltage 2nd sample
291
                        if(BoardRelease == 10) AdValueGyroYaw = (gyroyaw + 1) / 2; // analog gain on board 1.0 is 2 times higher
292
                        else
293
                        if(BoardRelease == 20) AdValueGyroYaw = 2047 - gyroyaw; // 2 times higher than a single sample
294
                        else                   AdValueGyroYaw = gyroyaw;        // 2 times higher than a single sample
295
                        ad_channel = AD_ACC_ROLL;
296
                        break;
297
                case 13:
298
                        accroll += ADC; // get roll acc voltage 2nd sample
299
                        AdValueAccRoll = AdBiasAccRoll - accroll; // subtract bias
300
                        ad_channel = AD_ACC_NICK;
301
                        break;
302
                case 14:
303
                        accnick += ADC; // get nick acc voltage 2nd sample
304
                        AdValueAccNick = accnick  - AdBiasAccNick; // subtract bias
305
                        ad_channel = AD_GYRO_NICK;
1 ingob 306
            break;
1180 killagreg 307
        case 15:
308
                gyronick += ADC; // get nick gyro voltage 4th sample
309
                if(BoardRelease == 10) gyronick *= 2; // 8 times higer than a single sample, HW gain x2
310
                else gyronick *= 4; // 16 times higer than a single sample
311
                        AdValueGyroNick = gyronick / 8; // 2 times higher than a single sample
312
                        filtergyronick = (filtergyronick + gyronick) / 2; //(16 samples)/2 results in a factor of 8 higher than a single sample) see HIRES_GYRO_AMPLIFY
313
                        HiResGyroNick = filtergyronick - BiasHiResGyroNick;
314
                        FilterHiResGyroNick = (FilterHiResGyroNick + HiResGyroNick) / 2;
315
                        ad_channel = AD_GYRO_ROLL;
316
                        break;
317
        case 16:
318
                gyroroll += ADC; // get roll gyro voltage 4th sample
319
                if(BoardRelease == 10) gyroroll *= 2; // 8 times higer than a single sample, HW gain x2
320
                else gyroroll *= 4; // 16 times higer than a single sample
321
                        AdValueGyroRoll = gyroroll / 8; // 2 times higher than a single sample
322
                        filtergyroroll = (filtergyroroll + gyroroll) / 2; //(16 samples)/2 results in a factor of 8 higher than a single sample) see HIRES_GYRO_AMPLIFY
323
                        HiResGyroRoll = filtergyroroll - BiasHiResGyroRoll;
324
                        FilterHiResGyroRoll = (FilterHiResGyroRoll + HiResGyroRoll) / 2;
325
                        ad_channel = AD_AIRPRESS;
326
                        break;
327
                case 17:
328
                        state = 0; // restart sequence from beginning
329
            ADReady = 1; // mark
330
            MeasurementCounter++; // increment total measurement counter
331
                        // "break;" is missing to enable fall thru case 9 at the end of the sequence
332
                case 9:
333
                        tmpAirPressure += ADC; // sum adc values
334
                        if(++average_pressure >= 5) // if 5 values are summerized for averaging
335
                        {
336
                                tmpAirPressure /= 2;
337
                                ReadingAirPressure = ADC; // update meassured air pressure
338
                                HeightD = (31 * HeightD + (int16_t)FCParam.HeightD * (int16_t)(255 * ExpandBaro + StartAirPressure - tmpAirPressure - ReadingHeight)) / 32;  // D-Part = CurrentValue - OldValue
339
                                AirPressure = (tmpAirPressure + 7 * AirPressure + 4) / 8; // averaging using history
340
                                ReadingHeight = 255 * ExpandBaro + StartAirPressure - AirPressure;
341
                                average_pressure = 0; // reset air pressure measurement counter
342
                                tmpAirPressure /= 2;
343
                        }
344
                        ad_channel = AD_GYRO_NICK;
345
                        break;
346
                default:
347
                        ad_channel = AD_GYRO_NICK;
348
                        state = 0;
349
                        break;
350
        }
351
    // set adc muxer to next ad_channel
352
    ADMUX = (ADMUX & 0xE0) | ad_channel;
886 killagreg 353
    // after full cycle stop further interrupts
354
    if(state != 0) ADC_Enable();
1 ingob 355
}