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
();
}