Subversion Repositories FlightCtrl

Rev

Rev 1634 | Rev 1645 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1634 Rev 1635
1
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2
// + Copyright (c) 04.2007 Holger Buss
2
// + Copyright (c) 04.2007 Holger Buss
3
// + Nur für den privaten Gebrauch
3
// + Nur für den privaten Gebrauch
4
// + www.MikroKopter.com
4
// + www.MikroKopter.com
5
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6
// + Es gilt für das gesamte Projekt (Hardware, Software, Binärfiles, Sourcecode und Dokumentation),
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.
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
8
// + Sollten direkte oder indirekte kommerzielle Absichten verfolgt werden, ist mit uns (info@mikrokopter.de) Kontakt
9
// + bzgl. der Nutzungsbedingungen aufzunehmen.
9
// + bzgl. der Nutzungsbedingungen aufzunehmen.
10
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen,
10
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen,
11
// + Verkauf von Luftbildaufnahmen, usw.
11
// + Verkauf von Luftbildaufnahmen, usw.
12
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13
// + Werden Teile des Quellcodes (mit oder ohne Modifikation) weiterverwendet oder veröffentlicht,
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
14
// + unterliegen sie auch diesen Nutzungsbedingungen und diese Nutzungsbedingungen incl. Copyright müssen dann beiliegen
15
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16
// + Sollte die Software (auch auszugesweise) oder sonstige Informationen des MikroKopter-Projekts
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"
17
// + auf anderen Webseiten oder sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
18
// + eindeutig als Ursprung verlinkt werden
18
// + eindeutig als Ursprung verlinkt werden
19
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion
20
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion
21
// + Benutzung auf eigene Gefahr
21
// + Benutzung auf eigene Gefahr
22
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden
22
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden
23
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24
// + Die Portierung der Software (oder Teile davon) auf andere Systeme (ausser der Hardware von www.mikrokopter.de) ist nur
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
25
// + mit unserer Zustimmung zulässig
26
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
26
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
27
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen
27
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen
28
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
28
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
29
// + Redistributions of source code (with or without modifications) must retain the above copyright notice,
29
// + Redistributions of source code (with or without modifications) must retain the above copyright notice,
30
// + this list of conditions and the following disclaimer.
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
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.
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
33
// +   * The use of this project (hardware, software, binary files, sources and documentation) is only permittet
34
// +     for non-commercial use (directly or indirectly)
34
// +     for non-commercial use (directly or indirectly)
35
// +     Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
35
// +     Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
36
// +     with our written permission
36
// +     with our written permission
37
// +   * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be
37
// +   * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be
38
// +     clearly linked as origin
38
// +     clearly linked as origin
39
// +   * porting to systems other than hardware from www.mikrokopter.de is not allowed
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"
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
41
// +  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
// +  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42
// +  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
// +  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
43
// +  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
44
// +  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
44
// +  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45
// +  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
45
// +  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46
// +  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
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)
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
48
// +  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49
// +  POSSIBILITY OF SUCH DAMAGE.
49
// +  POSSIBILITY OF SUCH DAMAGE.
50
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
50
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
51
#include <stdlib.h>
51
#include <stdlib.h>
52
#include <avr/io.h>
52
#include <avr/io.h>
53
#include <avr/interrupt.h>
53
#include <avr/interrupt.h>
54
 
54
 
55
#include "rc.h"
55
#include "rc.h"
56
#include "controlMixer.h"
56
#include "controlMixer.h"
57
#include "configuration.h"
57
#include "configuration.h"
58
 
58
 
59
// for DebugOut only.
59
// for DebugOut only.
60
#include "uart0.h"
60
#include "uart0.h"
61
 
61
 
62
 
62
 
63
// The channel array is 1-based. The 0th entry is not used.
63
// The channel array is 1-based. The 0th entry is not used.
64
volatile int16_t PPM_in[MAX_CHANNELS];
64
volatile int16_t PPM_in[MAX_CHANNELS];
65
volatile int16_t PPM_diff[MAX_CHANNELS];
65
volatile int16_t PPM_diff[MAX_CHANNELS];
66
volatile uint8_t NewPpmData = 1;
66
volatile uint8_t NewPpmData = 1;
67
volatile int16_t RC_Quality = 0;
67
volatile int16_t RC_Quality = 0;
68
int16_t RC_PRTY[4];
68
int16_t RC_PRTY[4];
69
 
69
 
70
int16_t stickOffsetPitch = 0, stickOffsetRoll = 0;
70
int16_t stickOffsetPitch = 0, stickOffsetRoll = 0;
71
 
71
 
72
/***************************************************************
72
/***************************************************************
73
 *  16bit timer 1 is used to decode the PPM-Signal            
73
 *  16bit timer 1 is used to decode the PPM-Signal            
74
 ***************************************************************/
74
 ***************************************************************/
75
void RC_Init (void) {
75
void RC_Init (void) {
76
  uint8_t sreg = SREG;
76
  uint8_t sreg = SREG;
77
 
77
 
78
  // disable all interrupts before reconfiguration
78
  // disable all interrupts before reconfiguration
79
  cli();
79
  cli();
80
 
80
 
81
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
81
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
82
  DDRD &= ~(1<<DDD6);
82
  DDRD &= ~(1<<DDD6);
83
  PORTD |= (1<<PORTD6);
83
  PORTD |= (1<<PORTD6);
84
 
84
 
85
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
85
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
86
  // set as output
86
  // set as output
87
  DDRD |= /*(1<<DDD5)|*/(1<<DDD4);
87
  DDRD |= /*(1<<DDD5)|*/(1<<DDD4);
88
  // low level
88
  // low level
89
  PORTD &= ~(/*(1<<PORTD5)|*/(1<<PORTD4));
89
  PORTD &= ~(/*(1<<PORTD5)|*/(1<<PORTD4));
90
 
90
 
91
  // PD3 can't be used if 2nd UART is activated
91
  // PD3 can't be used if 2nd UART is activated
92
  // because TXD1 is at that port
92
  // because TXD1 is at that port
93
  if(CPUType != ATMEGA644P) {
93
  if(CPUType != ATMEGA644P) {
94
    DDRD |= (1<<PORTD3);
94
    DDRD |= (1<<PORTD3);
95
    PORTD &= ~(1<<PORTD3);
95
    PORTD &= ~(1<<PORTD3);
96
  }
96
  }
97
 
97
 
98
  // Timer/Counter1 Control Register A, B, C
98
  // Timer/Counter1 Control Register A, B, C
99
 
99
 
100
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
100
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
101
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
101
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
102
  // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
102
  // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
103
  // Enable input capture noise cancler (bit: ICNC1=1)
103
  // Enable input capture noise cancler (bit: ICNC1=1)
104
  // Trigger on positive edge of the input capture pin (bit: ICES1=1),
104
  // Trigger on positive edge of the input capture pin (bit: ICES1=1),
105
  // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2µs
105
  // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2µs
106
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
106
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
107
  TCCR1A &= ~((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<WGM11)|(1<<WGM10));
107
  TCCR1A &= ~((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<WGM11)|(1<<WGM10));
108
  TCCR1B &= ~((1<<WGM13)|(1<<WGM12)|(1<<CS12));
108
  TCCR1B &= ~((1<<WGM13)|(1<<WGM12)|(1<<CS12));
109
  TCCR1B |= (1<<CS11)|(1<<CS10)|(1<<ICES1)|(1<<ICNC1);
109
  TCCR1B |= (1<<CS11)|(1<<CS10)|(1<<ICES1)|(1<<ICNC1);
110
  TCCR1C &= ~((1<<FOC1A)|(1<<FOC1B));
110
  TCCR1C &= ~((1<<FOC1A)|(1<<FOC1B));
111
 
111
 
112
  // Timer/Counter1 Interrupt Mask Register
112
  // Timer/Counter1 Interrupt Mask Register
113
 
113
 
114
  // Enable Input Capture Interrupt (bit: ICIE1=1)
114
  // Enable Input Capture Interrupt (bit: ICIE1=1)
115
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
115
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
116
  // Enable Overflow Interrupt (bit: TOIE1=0)
116
  // Enable Overflow Interrupt (bit: TOIE1=0)
117
  TIMSK1 &= ~((1<<OCIE1B)|(1<<OCIE1A)|(1<<TOIE1));
117
  TIMSK1 &= ~((1<<OCIE1B)|(1<<OCIE1A)|(1<<TOIE1));
118
  TIMSK1 |= (1<<ICIE1);
118
  TIMSK1 |= (1<<ICIE1);
119
 
119
 
120
  RC_Quality = 0;
120
  RC_Quality = 0;
121
 
121
 
122
  SREG = sreg;
122
  SREG = sreg;
123
}
123
}
124
 
124
 
125
 
125
 
126
/********************************************************************/
126
/********************************************************************/
127
/*         Every time a positive edge is detected at PD6            */
127
/*         Every time a positive edge is detected at PD6            */
128
/********************************************************************/
128
/********************************************************************/
129
/*                               t-Frame
129
/*                               t-Frame
130
                                 <----------------------------------------------------------------------->
130
                                 <----------------------------------------------------------------------->
131
                                 ____   ______   _____   ________                ______    sync gap      ____
131
                                 ____   ______   _____   ________                ______    sync gap      ____
132
                                 |    | |      | |     | |        |              |      |                |
132
                                 |    | |      | |     | |        |              |      |                |
133
                                 |    | |      | |     | |        |              |      |                |
133
                                 |    | |      | |     | |        |              |      |                |
134
                              ___|    |_|      |_|     |_|        |_.............|      |________________|
134
                              ___|    |_|      |_|     |_|        |_.............|      |________________|
135
                                 <-----><-------><------><-------->              <------>                <---
135
                                 <-----><-------><------><-------->              <------>                <---
136
                                 t0       t1      t2       t4                     tn                     t0
136
                                 t0       t1      t2       t4                     tn                     t0
137
 
137
 
138
                                 The PPM-Frame length is 22.5 ms.
138
                                 The PPM-Frame length is 22.5 ms.
139
                                 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
139
                                 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
140
                                 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
140
                                 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
141
                                 The maximum time delay of two events coding a chanel is ( 1.7 + 0.3) ms = 2 ms.
141
                                 The maximum time delay of two events coding a chanel is ( 1.7 + 0.3) ms = 2 ms.
142
                                 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
142
                                 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
143
                                 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
143
                                 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
144
                                 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
144
                                 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
145
                                 the syncronization gap.
145
                                 the syncronization gap.
146
*/
146
*/
147
ISR(TIMER1_CAPT_vect) { // typical rate of 1 ms to 2 ms
147
ISR(TIMER1_CAPT_vect) { // typical rate of 1 ms to 2 ms
148
  int16_t signal = 0, tmp;
148
  int16_t signal = 0, tmp;
149
  static int16_t index;
149
  static int16_t index;
150
  static uint16_t oldICR1 = 0;
150
  static uint16_t oldICR1 = 0;
151
 
151
 
152
  // 16bit Input Capture Register ICR1 contains the timer value TCNT1
152
  // 16bit Input Capture Register ICR1 contains the timer value TCNT1
153
  // at the time the edge was detected
153
  // at the time the edge was detected
154
 
154
 
155
  // calculate the time delay to the previous event time which is stored in oldICR1
155
  // calculate the time delay to the previous event time which is stored in oldICR1
156
  // calculatiing the difference of the two uint16_t and converting the result to an int16_t
156
  // calculatiing the difference of the two uint16_t and converting the result to an int16_t
157
  // implicit handles a timer overflow 65535 -> 0 the right way.
157
  // implicit handles a timer overflow 65535 -> 0 the right way.
158
  signal = (uint16_t) ICR1 - oldICR1;
158
  signal = (uint16_t) ICR1 - oldICR1;
159
  oldICR1 = ICR1;
159
  oldICR1 = ICR1;
160
 
160
 
161
  //sync gap? (3.52 ms < signal < 25.6 ms)
161
  //sync gap? (3.52 ms < signal < 25.6 ms)
162
  if((signal > 1100) && (signal < 8000)) {
162
  if((signal > 1100) && (signal < 8000)) {
163
    // if a sync gap happens and there where at least 4 channels decoded before
163
    // if a sync gap happens and there where at least 4 channels decoded before
164
    // then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
164
    // then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
165
    if(index >= 4) {
165
    if(index >= 4) {
166
      NewPpmData = 0;  // Null means NewData for the first 4 channels
166
      NewPpmData = 0;  // Null means NewData for the first 4 channels
167
    }
167
    }
168
    // synchronize channel index
168
    // synchronize channel index
169
    index = 1;
169
    index = 1;
170
  } else { // within the PPM frame
170
  } else { // within the PPM frame
171
    if(index < MAX_CHANNELS-1) // PPM24 supports 12 channels
171
    if(index < MAX_CHANNELS-1) // PPM24 supports 12 channels
172
      {
172
      {
173
        // check for valid signal length (0.8 ms < signal < 2.1984 ms)
173
        // check for valid signal length (0.8 ms < signal < 2.1984 ms)
174
        // signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
174
        // signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
175
        if((signal > 250) && (signal < 687))
175
        if((signal > 250) && (signal < 687))
176
          {
176
          {
177
            // shift signal to zero symmetric range  -154 to 159
177
            // shift signal to zero symmetric range  -154 to 159
178
            signal -= 466; // offset of 1.4912 ms ??? (469 * 3.2µs = 1.5008 ms)
178
            signal -= 466; // offset of 1.4912 ms ??? (469 * 3.2µs = 1.5008 ms)
179
            // check for stable signal
179
            // check for stable signal
180
            if(abs(signal - PPM_in[index]) < 6) {
180
            if(abs(signal - PPM_in[index]) < 6) {
181
              if(RC_Quality < 200) RC_Quality +=10;
181
              if(RC_Quality < 200) RC_Quality +=10;
182
              else RC_Quality = 200;
182
              else RC_Quality = 200;
183
            }
183
            }
184
            // calculate exponential history for signal
184
            // calculate exponential history for signal
185
            tmp = (3 * PPM_in[index] + signal) / 4;
185
            tmp = (3 * PPM_in[index] + signal) / 4;
186
            if(tmp > signal + 1) tmp--; else
186
            if(tmp > signal + 1) tmp--; else
187
              if(tmp < signal-1) tmp++;
187
              if(tmp < signal-1) tmp++;
188
            // calculate signal difference on good signal level
188
            // calculate signal difference on good signal level
189
            if(RC_Quality >= 195)  
189
            if(RC_Quality >= 195)  
190
              PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for nois reduction
190
              PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for nois reduction
191
            else PPM_diff[index] = 0;
191
            else PPM_diff[index] = 0;
192
            PPM_in[index] = tmp; // update channel value
192
            PPM_in[index] = tmp; // update channel value
193
          }
193
          }
194
        index++; // next channel
194
        index++; // next channel
195
        // demux sum signal for channels 5 to 7 to J3, J4, J5
195
        // demux sum signal for channels 5 to 7 to J3, J4, J5
196
        // TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
196
        // TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
197
        // channels are usually available at the receiver anyway.
197
        // channels are usually available at the receiver anyway.
198
        // if(index == 5) J3HIGH; else J3LOW;
198
        // if(index == 5) J3HIGH; else J3LOW;
199
        // if(index == 6) J4HIGH; else J4LOW;
199
        // if(index == 6) J4HIGH; else J4LOW;
200
        // if(CPUType != ATMEGA644P) // not used as TXD1
200
        // if(CPUType != ATMEGA644P) // not used as TXD1
201
        //  {
201
        //  {
202
        //    if(index == 7) J5HIGH; else J5LOW;
202
        //    if(index == 7) J5HIGH; else J5LOW;
203
        //  }
203
        //  }
204
      }
204
      }
205
  }
205
  }
206
}
206
}
207
 
207
 
208
#define RCChannel(dimension) PPM_in[staticParams.ChannelAssignment[dimension]]
208
#define RCChannel(dimension) PPM_in[staticParams.ChannelAssignment[dimension]]
209
#define RCDiff(dimension) PPM_diff[staticParams.ChannelAssignment[dimension]]
209
#define RCDiff(dimension) PPM_diff[staticParams.ChannelAssignment[dimension]]
210
 
210
 
211
/*
211
/*
212
 * This must be called (as the only thing) for each control loop cycle (488 Hz).
212
 * This must be called (as the only thing) for each control loop cycle (488 Hz).
213
 */
213
 */
214
void RC_update() {
214
void RC_update() {
215
  int16_t tmp1, tmp2;
215
  int16_t tmp1, tmp2;
216
  if(RC_Quality) {
216
  if(RC_Quality) {
217
    RC_Quality--;
217
    RC_Quality--;
218
    if (NewPpmData-- == 0) {
218
    if (NewPpmData-- == 0) {
219
 
-
 
220
      DebugOut.Analog[12] = stickOffsetPitch;
-
 
221
      DebugOut.Analog[13] = stickOffsetRoll;
-
 
222
 
-
 
223
      RC_PRTY[CONTROL_PITCH] = (RCChannel(CH_PITCH) - stickOffsetPitch) * staticParams.StickP + RCDiff(CH_PITCH) * staticParams.StickD;
219
      RC_PRTY[CONTROL_PITCH] = (RCChannel(CH_PITCH) - stickOffsetPitch) * staticParams.StickP + RCDiff(CH_PITCH) * staticParams.StickD;
224
      RC_PRTY[CONTROL_ROLL] = (RCChannel(CH_ROLL) - stickOffsetRoll)    * staticParams.StickP + RCDiff(CH_ROLL)  * staticParams.StickD;
220
      RC_PRTY[CONTROL_ROLL] =  (RCChannel(CH_ROLL) - stickOffsetRoll)   * staticParams.StickP + RCDiff(CH_ROLL)  * staticParams.StickD;
225
      RC_PRTY[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE) + PPM_diff[staticParams.ChannelAssignment[CH_THROTTLE]] * dynamicParams.UserParams[6] + 120;
221
      RC_PRTY[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE) + PPM_diff[staticParams.ChannelAssignment[CH_THROTTLE]] * dynamicParams.UserParams[3] + 120;
226
      if (RC_PRTY[CONTROL_THROTTLE] < 0) RC_PRTY[CONTROL_THROTTLE] = 0; // Throttle is non negative.
222
      if (RC_PRTY[CONTROL_THROTTLE] < 0) RC_PRTY[CONTROL_THROTTLE] = 0; // Throttle is non negative.
227
      tmp1 = -RCChannel(CH_YAW) - RCDiff(CH_YAW);
223
      tmp1 = -RCChannel(CH_YAW) - RCDiff(CH_YAW);
228
      // exponential stick sensitivity in yawring rate
224
      // exponential stick sensitivity in yawring rate
229
      tmp2 = (int32_t) staticParams.StickYawP * ((int32_t)tmp1 * abs(tmp1)) / 512L; // expo  y = ax + bx^2
225
      tmp2 = (int32_t) staticParams.StickYawP * ((int32_t)tmp1 * abs(tmp1)) / 512L; // expo  y = ax + bx^2
230
      tmp2 += (staticParams.StickYawP * tmp1) / 4;
226
      tmp2 += (staticParams.StickYawP * tmp1) / 4;
231
      RC_PRTY[CONTROL_YAW] = tmp2;
227
      RC_PRTY[CONTROL_YAW] = tmp2;
232
    }
228
    }
233
  } else { // Bad signal
229
  } else { // Bad signal
234
    RC_PRTY[CONTROL_PITCH] = RC_PRTY[CONTROL_ROLL] = RC_PRTY[CONTROL_THROTTLE] = RC_PRTY[CONTROL_YAW] = 0;
230
    RC_PRTY[CONTROL_PITCH] = RC_PRTY[CONTROL_ROLL] = RC_PRTY[CONTROL_THROTTLE] = RC_PRTY[CONTROL_YAW] = 0;
235
  }
231
  }
236
}
232
}
237
 
233
 
238
/*
234
/*
239
 * Get Pitch, Roll, Throttle, Yaw values
235
 * Get Pitch, Roll, Throttle, Yaw values
240
 */
236
 */
241
int16_t* RC_getPRTY(void) {
237
int16_t* RC_getPRTY(void) {
242
  return RC_PRTY;
238
  return RC_PRTY;
243
}
239
}
244
 
240
 
245
/*
241
/*
246
 * Get other channel value
242
 * Get other channel value
247
 */
243
 */
248
int16_t RC_getVariable(uint8_t varNum) {
244
int16_t RC_getVariable(uint8_t varNum) {
249
  if (varNum < 4)
245
  if (varNum < 4)
250
    // 0th variable is 5th channel (1-based) etc.
246
    // 0th variable is 5th channel (1-based) etc.
251
    return RCChannel(varNum + 5);
247
    return RCChannel(varNum + 5);
252
  /*
248
  /*
253
   * Let's just say:
249
   * Let's just say:
254
   * The RC variable 4 is hardwired to channel 5
250
   * The RC variable 4 is hardwired to channel 5
255
   * The RC variable 5 is hardwired to channel 6
251
   * The RC variable 5 is hardwired to channel 6
256
   * The RC variable 6 is hardwired to channel 7
252
   * The RC variable 6 is hardwired to channel 7
257
   * The RC variable 7 is hardwired to channel 8
253
   * The RC variable 7 is hardwired to channel 8
258
   * Alternatively, one could bind them to channel (4 + varNum) - or whatever...
254
   * Alternatively, one could bind them to channel (4 + varNum) - or whatever...
259
   */
255
   */
260
  return PPM_in[varNum + 1];
256
  return PPM_in[varNum + 1];
261
}
257
}
262
 
258
 
263
uint8_t RC_getSignalQuality(void) {
259
uint8_t RC_getSignalQuality(void) {
264
  if (RC_Quality >= 160)
260
  if (RC_Quality >= 160)
265
    return SIGNAL_GOOD;
261
    return SIGNAL_GOOD;
266
  if (RC_Quality >= 140)
262
  if (RC_Quality >= 140)
267
    return SIGNAL_OK;
263
    return SIGNAL_OK;
268
  if (RC_Quality >= 120)
264
  if (RC_Quality >= 120)
269
    return SIGNAL_BAD;
265
    return SIGNAL_BAD;
270
  return SIGNAL_LOST;
266
  return SIGNAL_LOST;
271
}
267
}
272
 
268
 
273
/*
269
/*
274
 * To should fired only when the right stick is in the center position.
270
 * To should fired only when the right stick is in the center position.
275
 * This will cause the value of pitch and roll stick to be adjusted
271
 * This will cause the value of pitch and roll stick to be adjusted
276
 * to zero (not just to near zero, as per the assumption in rc.c
272
 * to zero (not just to near zero, as per the assumption in rc.c
277
 * about the rc signal. I had values about 50..70 with a Futaba
273
 * about the rc signal. I had values about 50..70 with a Futaba
278
 * R617 receiver.) This calibration is not strictly necessary, but
274
 * R617 receiver.) This calibration is not strictly necessary, but
279
 * for control logic that depends on the exact (non)center position
275
 * for control logic that depends on the exact (non)center position
280
 * of a stick, it may be useful.
276
 * of a stick, it may be useful.
281
 */
277
 */
282
void RC_calibrate(void) {
278
void RC_calibrate(void) {
283
  if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
279
  if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
284
    // In HH, it s OK to trim the R/C. The effect should not be conteracted here.
280
    // In HH, it s OK to trim the R/C. The effect should not be conteracted here.
285
    stickOffsetPitch = stickOffsetRoll = 0;
281
    stickOffsetPitch = stickOffsetRoll = 0;
286
  } else {
282
  } else {
287
    stickOffsetPitch = RCChannel(CH_PITCH);
283
    stickOffsetPitch = RCChannel(CH_PITCH);
288
    stickOffsetRoll = RCChannel(CH_ROLL);
284
    stickOffsetRoll = RCChannel(CH_ROLL);
289
  }
285
  }
290
}
286
}
291
 
287
 
292
#define COMMAND_THRESHOLD 85
288
#define COMMAND_THRESHOLD 85
-
 
289
#define COMMAND_CHANNEL_VERTICAL CH_THROTTLE
-
 
290
#define COMMAND_CHANNEL_HORIZONTAL CH_YAW
-
 
291
 
293
uint8_t RC_getCommand(void) {
292
uint8_t RC_getCommand(void) {
294
  if(RCChannel(CH_THROTTLE) > COMMAND_THRESHOLD) {
293
  if(RCChannel(COMMAND_CHANNEL_VERTICAL) > COMMAND_THRESHOLD) {
295
    // throttle is up
294
    // vertical is up
296
    if(RCChannel(CH_YAW) > COMMAND_THRESHOLD)
295
    if(RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
297
      return COMMAND_GYROCAL;
296
      return COMMAND_GYROCAL;
298
    if(RCChannel(CH_YAW) < -COMMAND_THRESHOLD)
297
    if(RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
299
      return COMMAND_ACCCAL;
298
      return COMMAND_ACCCAL;
300
    return COMMAND_NONE;
299
    return COMMAND_NONE;
301
  } else if(RCChannel(CH_THROTTLE) < -COMMAND_THRESHOLD) {
300
  } else if(RCChannel(COMMAND_CHANNEL_VERTICAL) < -COMMAND_THRESHOLD) {
302
    // pitch is down
301
    // vertical is down
303
    if(RCChannel(CH_YAW) > COMMAND_THRESHOLD)
302
    if(RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
304
      return COMMAND_STOP;
303
      return COMMAND_STOP;
305
    if(RCChannel(CH_YAW) < -COMMAND_THRESHOLD)
304
    if(RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
306
      return COMMAND_START;
305
      return COMMAND_START;
307
    return COMMAND_NONE;
306
    return COMMAND_NONE;
308
  } else {
307
  } else {
309
    // pitch is around center
308
    // vertical is around center
310
    return COMMAND_NONE;
309
    return COMMAND_NONE;
311
  }
310
  }
312
}
311
}
313
 
312
 
314
/*
313
/*
315
 * Command arguments on R/C:
314
 * Command arguments on R/C:
316
 * 2--3--4
315
 * 2--3--4
317
 * |     |  +
316
 * |     |  +
318
 * 1  0  5  ^ 0
317
 * 1  0  5  ^ 0
319
 * |     |  |  
318
 * |     |  |  
320
 * 8--7--6
319
 * 8--7--6
321
 *    
320
 *    
322
 * + <--
321
 * + <--
323
 *    0
322
 *    0
324
 *
323
 *
325
 * Not in any of these positions: 0
324
 * Not in any of these positions: 0
326
 */
325
 */
-
 
326
 
327
#define ARGUMENT_THRESHOLD 70
327
#define ARGUMENT_THRESHOLD 70
-
 
328
#define ARGUMENT_CHANNEL_VERTICAL CH_PITCH
-
 
329
#define ARGUMENT_CHANNEL_HORIZONTAL CH_ROLL
-
 
330
 
328
uint8_t RC_getArgument(void) {
331
uint8_t RC_getArgument(void) {
329
  if(RCChannel(CH_PITCH) > ARGUMENT_THRESHOLD) {
332
  if(RCChannel(ARGUMENT_CHANNEL_VERTICAL) > ARGUMENT_THRESHOLD) {
330
    // pitch is up
333
    // vertical is up
331
    if(RCChannel(CH_ROLL) > ARGUMENT_THRESHOLD)
334
    if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
332
      return 2;
335
      return 2;
333
    if(RCChannel(CH_ROLL) < -ARGUMENT_THRESHOLD)
336
    if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
334
      return 4;
337
      return 4;
335
    return 3;
338
    return 3;
336
  } else if(RCChannel(CH_PITCH) < -ARGUMENT_THRESHOLD) {
339
  } else if(RCChannel(ARGUMENT_CHANNEL_VERTICAL) < -ARGUMENT_THRESHOLD) {
337
    // pitch is down
340
    // vertical is down
338
    if(RCChannel(CH_ROLL) > ARGUMENT_THRESHOLD)
341
    if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
339
      return 8;
342
      return 8;
340
    if(RCChannel(CH_ROLL) < -ARGUMENT_THRESHOLD)
343
    if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
341
      return 6;
344
      return 6;
342
    return 7;
345
    return 7;
343
  } else {
346
  } else {
344
    // pitch is around center
347
    // vertical is around center
345
    if(RCChannel(CH_ROLL) > ARGUMENT_THRESHOLD)
348
    if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
346
      return 1;
349
      return 1;
347
    if(RCChannel(CH_ROLL) < -ARGUMENT_THRESHOLD)
350
    if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
348
      return 5;
351
      return 5;
349
    return 0;
352
    return 0;
350
  }
353
  }
351
}
354
}
352
 
355
 
353
uint8_t RC_getLooping(uint8_t looping) {
356
uint8_t RC_getLooping(uint8_t looping) {
354
  //  static uint8_t looping = 0;
357
  //  static uint8_t looping = 0;
355
 
358
 
356
  if(RCChannel(CH_ROLL) > staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_LEFT) {
359
  if(RCChannel(CH_ROLL) > staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_LEFT) {
357
    looping |= (LOOPING_ROLL_AXIS | LOOPING_LEFT);
360
    looping |= (LOOPING_ROLL_AXIS | LOOPING_LEFT);
358
  } else if((looping & LOOPING_LEFT) && RCChannel(CH_ROLL) < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
361
  } else if((looping & LOOPING_LEFT) && RCChannel(CH_ROLL) < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
359
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_LEFT));
362
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_LEFT));
360
  }
363
  }
361
 
364
 
362
  if(RCChannel(CH_ROLL) < -staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_RIGHT) {
365
  if(RCChannel(CH_ROLL) < -staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_RIGHT) {
363
    looping |= (LOOPING_ROLL_AXIS | LOOPING_RIGHT);
366
    looping |= (LOOPING_ROLL_AXIS | LOOPING_RIGHT);
364
  } else if((looping & LOOPING_RIGHT) && RCChannel(CH_ROLL) > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
367
  } else if((looping & LOOPING_RIGHT) && RCChannel(CH_ROLL) > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
365
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_RIGHT));
368
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_RIGHT));
366
  }
369
  }
367
 
370
 
368
  if(RCChannel(CH_PITCH) > staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_UP) {
371
  if(RCChannel(CH_PITCH) > staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_UP) {
369
    looping |= (LOOPING_PITCH_AXIS | LOOPING_UP);
372
    looping |= (LOOPING_PITCH_AXIS | LOOPING_UP);
370
  } else if((looping & LOOPING_UP) && RCChannel(CH_PITCH) < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
373
  } else if((looping & LOOPING_UP) && RCChannel(CH_PITCH) < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
371
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_UP));
374
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_UP));
372
  }
375
  }
373
 
376
 
374
  if(RCChannel(CH_PITCH) < -staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_DOWN) {
377
  if(RCChannel(CH_PITCH) < -staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_DOWN) {
375
    looping |= (LOOPING_PITCH_AXIS | LOOPING_DOWN);
378
    looping |= (LOOPING_PITCH_AXIS | LOOPING_DOWN);
376
  } else if((looping & LOOPING_DOWN) && RCChannel(CH_PITCH) > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
379
  } else if((looping & LOOPING_DOWN) && RCChannel(CH_PITCH) > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
377
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_DOWN));
380
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_DOWN));
378
  }
381
  }
379
 
382
 
380
  return looping;
383
  return looping;
381
}
384
}
382
 
385
 
383
/*
386
/*
384
 * Abstract controls are not used at the moment.
387
 * Abstract controls are not used at the moment.
385
 t_control rc_control = {
388
 t_control rc_control = {
386
 RC_getPitch,
389
 RC_getPitch,
387
 RC_getRoll,
390
 RC_getRoll,
388
 RC_getYaw,
391
 RC_getYaw,
389
 RC_getThrottle,
392
 RC_getThrottle,
390
 RC_getSignalQuality,
393
 RC_getSignalQuality,
391
 RC_calibrate
394
 RC_calibrate
392
 };
395
 };
393
*/
396
*/
394
 
397