Subversion Repositories FlightCtrl

Rev

Rev 2122 | Rev 2135 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1910 - 1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
 
5
#include "rc.h"
6
#include "controlMixer.h"
7
#include "configuration.h"
8
#include "commands.h"
2099 - 9
#include "output.h"
1910 - 10
 
2099 - 11
// The channel array is 0-based!
1910 - 12
volatile int16_t PPM_in[MAX_CHANNELS];
2124 - 13
volatile uint16_t RC_buffer[MAX_CHANNELS];
14
volatile uint8_t inBfrPnt = 0;
15
 
2099 - 16
volatile uint8_t RCQuality;
2102 - 17
 
1910 - 18
uint8_t lastRCCommand = COMMAND_NONE;
2102 - 19
uint8_t lastFlightMode = FLIGHT_MODE_NONE;
20
 
2110 - 21
#define TIME(s) ((int16_t)(((long)F_CPU/(long)8000)*(float)s))
2115 - 22
 
1910 - 23
/***************************************************************
24
 *  16bit timer 1 is used to decode the PPM-Signal            
25
 ***************************************************************/
26
void RC_Init(void) {
27
  uint8_t sreg = SREG;
28
 
29
  // disable all interrupts before reconfiguration
30
  cli();
31
 
32
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
2099 - 33
  DDRD &= ~(1<<6);
34
  PORTD |= (1<<PORTD6);
1910 - 35
 
36
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
37
  // set as output
2099 - 38
  DDRD |= (1<<DDD5) | (1<<DDD4) | (1<<DDD3);
1910 - 39
  // low level
2099 - 40
  PORTD &= ~((1<<PORTD5) | (1<<PORTD4) | (1<<PORTD3));
1910 - 41
 
42
  // PD3 can't be used if 2nd UART is activated
43
  // because TXD1 is at that port
44
  if (CPUType != ATMEGA644P) {
2099 - 45
    DDRD |= (1<<PORTD3);
46
    PORTD &= ~(1<<PORTD3);
1910 - 47
  }
48
 
49
  // Timer/Counter1 Control Register A, B, C
50
 
51
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
52
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
2119 - 53
  // Set clock source to SYSCLK/8 (bit: CS12=0, CS11=1, CS10=0)
1910 - 54
  // Enable input capture noise cancler (bit: ICNC1=1)
55
  // Trigger on positive edge of the input capture pin (bit: ICES1=1),
2099 - 56
  // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2�s
1910 - 57
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
2119 - 58
  TCCR1A &= ~((1<<COM1A1)| (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11) | (1<<WGM10));
59
  TCCR1B &= ~((1<<WGM13) | (1<<WGM12)  | (1<<CS12));
60
  TCCR1B |= (1<<CS11)    | (1<<ICNC1);
61
  TCCR1C &= ~((1<<FOC1A) | (1<<FOC1B));
1910 - 62
 
2119 - 63
  if (channelMap.RCPolarity) {
64
    TCCR1B |= (1<<ICES1);
65
  } else {
66
    TCCR1B &= ~(1<<ICES1);
67
  }
68
 
1910 - 69
  // Timer/Counter1 Interrupt Mask Register
70
  // Enable Input Capture Interrupt (bit: ICIE1=1)
71
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
72
  // Enable Overflow Interrupt (bit: TOIE1=0)
2099 - 73
  TIMSK1 &= ~((1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1));
74
  TIMSK1 |= (1<<ICIE1);
1910 - 75
 
2099 - 76
  RCQuality = 0;
1910 - 77
 
78
  SREG = sreg;
79
}
80
 
2124 - 81
/*
82
 * This new and much faster interrupt handler should reduce servo jolts.
83
 */
84
ISR(TIMER1_CAPT_vect) {
85
  static uint16_t oldICR1 = 0;
86
  uint16_t signal = (uint16_t)ICR1 - oldICR1;
87
  oldICR1 = ICR1;
88
  //sync gap? (3.5 ms < signal < 25.6 ms)
89
  if (signal > TIME(3.5)) {
90
        inBfrPnt = 0;
91
  } else if (inBfrPnt<MAX_CHANNELS) {
92
        RC_buffer[inBfrPnt++] = signal;
93
  }
94
}
95
 
1910 - 96
/********************************************************************/
97
/*         Every time a positive edge is detected at PD6            */
98
/********************************************************************/
99
/*                               t-Frame
2099 - 100
    <----------------------------------------------------------------------->
101
     ____   ______   _____   ________                ______    sync gap      ____
102
    |    | |      | |     | |        |              |      |                |
103
    |    | |      | |     | |        |              |      |                |
1910 - 104
 ___|    |_|      |_|     |_|        |_.............|      |________________|
2099 - 105
    <-----><-------><------><-----------            <------>                <---
1910 - 106
 t0       t1      t2       t4                     tn                     t0
107
 
108
 The PPM-Frame length is 22.5 ms.
109
 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
110
 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
2099 - 111
 The maximum time delay of two events coding a channel is ( 1.7 + 0.3) ms = 2 ms.
1910 - 112
 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
113
 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
114
 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
115
 the syncronization gap.
116
 */
2124 - 117
void RC_process(void) {
118
        if (RCQuality) RCQuality--;
119
  for (uint8_t channel=0; channel<MAX_CHANNELS; channel++) {
120
        uint16_t signal = RC_buffer[channel];
121
        if (signal != 0) {
122
          RC_buffer[channel] = 0; // reset to flag value already used.
2110 - 123
      if ((signal >= TIME(0.8)) && (signal < TIME(2.2))) {
2122 - 124
        signal -= (TIME(1.5) - 128 + channelMap.HWTrim);
2124 - 125
        if (abs(signal - PPM_in[channel]) < TIME(0.05)) {
126
                // With 7 channels and 50 frames/sec, we get 350 channel values/sec.
2099 - 127
          if (RCQuality < 200)
2124 - 128
            RCQuality += 2;
1910 - 129
        }
2124 - 130
        PPM_in[channel] = signal;
1910 - 131
      }
132
    }
133
  }
2124 - 134
  debugOut.analog[31] = RCQuality;
1910 - 135
}
136
 
2099 - 137
#define RCChannel(dimension) PPM_in[channelMap.channels[dimension]]
1910 - 138
 
2103 - 139
uint8_t getControlModeSwitch(void) {
2109 - 140
        int16_t channel = RCChannel(CH_MODESWITCH);
2110 - 141
        uint8_t flightMode = channel < -TIME(0.17) ? FLIGHT_MODE_MANUAL : (channel > TIME(0.17) ? FLIGHT_MODE_ANGLES : FLIGHT_MODE_RATE);
2102 - 142
        return flightMode;
143
}
144
 
145
// Gyro calibration is performed as.... well mode switch with no throttle and no airspeed would be nice.
146
// Maybe simply: Very very low throttle.
147
// Throttle xlow for COMMAND_TIMER: GYROCAL (once).
148
// mode switched: CHMOD
149
 
150
uint8_t RC_getCommand(void) {
151
        uint8_t flightMode = getControlModeSwitch();
152
 
153
        if (lastFlightMode != flightMode) {
154
                lastFlightMode = flightMode;
155
                lastRCCommand = COMMAND_CHMOD;
156
                return lastRCCommand;
157
        }
158
 
2103 - 159
        int16_t channel = RCChannel(CH_THROTTLE);
2104 - 160
 
2110 - 161
        if (channel <= -TIME(0.55)) {
2124 - 162
          int16_t aux = RCChannel(COMMAND_CHANNEL_HORIZONTAL);
163
          if (abs(aux) >= TIME(0.3)) // If we pull on the stick, it is gyrocal. Else it is RC cal.
164
                lastRCCommand = COMMAND_GYROCAL;
165
          else
166
                lastRCCommand = COMMAND_RCCAL;
2103 - 167
        } else {
168
          lastRCCommand = COMMAND_NONE;
169
        }
2102 - 170
        return lastRCCommand;
171
}
172
 
173
uint8_t RC_getArgument(void) {
174
        return lastFlightMode;
175
}
176
 
1910 - 177
/*
2099 - 178
 * Get Pitch, Roll, Throttle, Yaw values
1910 - 179
 */
2103 - 180
void RC_periodicTaskAndPRYT(int16_t* PRYT) {
2124 - 181
  RC_process();
2099 - 182
 
2124 - 183
  PRYT[CONTROL_ELEVATOR]   = RCChannel(CH_ELEVATOR)   - rcTrim.trim[CH_ELEVATOR];
184
  PRYT[CONTROL_AILERONS]   = RCChannel(CH_AILERONS)   - rcTrim.trim[CH_AILERONS];
185
  PRYT[CONTROL_RUDDER]     = RCChannel(CH_RUDDER)     - rcTrim.trim[CH_RUDDER];
186
  PRYT[CONTROL_THROTTLE]   = RCChannel(CH_THROTTLE);  // no trim on throttle!
2102 - 187
 
2124 - 188
  debugOut.analog[20] = PRYT[CONTROL_ELEVATOR];
189
  debugOut.analog[21] = PRYT[CONTROL_AILERONS];
190
  debugOut.analog[22] = PRYT[CONTROL_RUDDER];
191
  debugOut.analog[23] = PRYT[CONTROL_THROTTLE];
1910 - 192
}
193
 
194
/*
195
 * Get other channel value
196
 */
197
int16_t RC_getVariable(uint8_t varNum) {
198
  if (varNum < 4)
199
    // 0th variable is 5th channel (1-based) etc.
2116 - 200
    return (RCChannel(varNum + CH_POTS) >> 3) + channelMap.variableOffset;
1910 - 201
  /*
202
   * Let's just say:
2099 - 203
   * The RC variable i is hardwired to channel i, i>=4
1910 - 204
   */
2116 - 205
  return (PPM_in[varNum] >> 3) + channelMap.variableOffset;
1910 - 206
}
207
 
208
uint8_t RC_getSignalQuality(void) {
2099 - 209
  if (RCQuality >= 160)
1910 - 210
    return SIGNAL_GOOD;
2099 - 211
  if (RCQuality >= 140)
1910 - 212
    return SIGNAL_OK;
2099 - 213
  if (RCQuality >= 120)
1910 - 214
    return SIGNAL_BAD;
215
  return SIGNAL_LOST;
216
}
217
 
218
void RC_calibrate(void) {
2122 - 219
  rcTrim.trim[CH_ELEVATOR] = RCChannel(CH_ELEVATOR);
220
  rcTrim.trim[CH_AILERONS] = RCChannel(CH_AILERONS);
221
  rcTrim.trim[CH_RUDDER]   = RCChannel(CH_RUDDER);
222
  rcTrim.trim[CH_THROTTLE] = 0;
1910 - 223
}
2115 - 224
 
2119 - 225
int16_t RC_getZeroThrottle(void) {
2115 - 226
        return TIME (-0.5);
227
}
2122 - 228
 
229
void RC_setZeroTrim(void) {
230
  for (uint8_t i=0; i<MAX_CHANNELS; i++) {
231
    rcTrim.trim[i] = 0;
232
  }
233
}