Subversion Repositories FlightCtrl

Rev

Rev 2136 | 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];
2173 - 14
volatile uint8_t inBfrPnt;
2124 - 15
 
2099 - 16
volatile uint8_t RCQuality;
2102 - 17
 
2173 - 18
uint8_t lastRCCommand;
19
uint8_t lastFlightMode;
2102 - 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);
75
  RCQuality = 0;
1910 - 76
  SREG = sreg;
77
}
78
 
2124 - 79
/*
80
 * This new and much faster interrupt handler should reduce servo jolts.
81
 */
82
ISR(TIMER1_CAPT_vect) {
83
  static uint16_t oldICR1 = 0;
84
  uint16_t signal = (uint16_t)ICR1 - oldICR1;
85
  oldICR1 = ICR1;
86
  //sync gap? (3.5 ms < signal < 25.6 ms)
87
  if (signal > TIME(3.5)) {
2173 - 88
    inBfrPnt = 0;
2124 - 89
  } else if (inBfrPnt<MAX_CHANNELS) {
2173 - 90
    RC_buffer[inBfrPnt++] = signal;
2124 - 91
  }
92
}
93
 
1910 - 94
/********************************************************************/
95
/*         Every time a positive edge is detected at PD6            */
96
/********************************************************************/
97
/*                               t-Frame
2099 - 98
    <----------------------------------------------------------------------->
99
     ____   ______   _____   ________                ______    sync gap      ____
100
    |    | |      | |     | |        |              |      |                |
101
    |    | |      | |     | |        |              |      |                |
1910 - 102
 ___|    |_|      |_|     |_|        |_.............|      |________________|
2099 - 103
    <-----><-------><------><-----------            <------>                <---
1910 - 104
 t0       t1      t2       t4                     tn                     t0
105
 
106
 The PPM-Frame length is 22.5 ms.
107
 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
108
 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
2099 - 109
 The maximum time delay of two events coding a channel is ( 1.7 + 0.3) ms = 2 ms.
1910 - 110
 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
111
 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
112
 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
113
 the syncronization gap.
114
 */
2124 - 115
void RC_process(void) {
2173 - 116
  if (RCQuality) RCQuality--;
2124 - 117
  for (uint8_t channel=0; channel<MAX_CHANNELS; channel++) {
118
        uint16_t signal = RC_buffer[channel];
119
        if (signal != 0) {
120
          RC_buffer[channel] = 0; // reset to flag value already used.
2110 - 121
      if ((signal >= TIME(0.8)) && (signal < TIME(2.2))) {
2122 - 122
        signal -= (TIME(1.5) - 128 + channelMap.HWTrim);
2124 - 123
        if (abs(signal - PPM_in[channel]) < TIME(0.05)) {
124
                // With 7 channels and 50 frames/sec, we get 350 channel values/sec.
2099 - 125
          if (RCQuality < 200)
2124 - 126
            RCQuality += 2;
1910 - 127
        }
2124 - 128
        PPM_in[channel] = signal;
1910 - 129
      }
130
    }
131
  }
132
}
133
 
2099 - 134
#define RCChannel(dimension) PPM_in[channelMap.channels[dimension]]
1910 - 135
 
2103 - 136
uint8_t getControlModeSwitch(void) {
2109 - 137
        int16_t channel = RCChannel(CH_MODESWITCH);
2110 - 138
        uint8_t flightMode = channel < -TIME(0.17) ? FLIGHT_MODE_MANUAL : (channel > TIME(0.17) ? FLIGHT_MODE_ANGLES : FLIGHT_MODE_RATE);
2102 - 139
        return flightMode;
140
}
141
 
142
// Gyro calibration is performed as.... well mode switch with no throttle and no airspeed would be nice.
143
// Maybe simply: Very very low throttle.
144
// Throttle xlow for COMMAND_TIMER: GYROCAL (once).
145
// mode switched: CHMOD
146
 
147
uint8_t RC_getCommand(void) {
148
        uint8_t flightMode = getControlModeSwitch();
149
 
150
        if (lastFlightMode != flightMode) {
151
                lastFlightMode = flightMode;
152
                lastRCCommand = COMMAND_CHMOD;
153
                return lastRCCommand;
154
        }
155
 
2103 - 156
        int16_t channel = RCChannel(CH_THROTTLE);
2104 - 157
 
2110 - 158
        if (channel <= -TIME(0.55)) {
2124 - 159
          int16_t aux = RCChannel(COMMAND_CHANNEL_HORIZONTAL);
160
          if (abs(aux) >= TIME(0.3)) // If we pull on the stick, it is gyrocal. Else it is RC cal.
161
                lastRCCommand = COMMAND_GYROCAL;
162
          else
163
                lastRCCommand = COMMAND_RCCAL;
2103 - 164
        } else {
165
          lastRCCommand = COMMAND_NONE;
166
        }
2102 - 167
        return lastRCCommand;
168
}
169
 
170
uint8_t RC_getArgument(void) {
171
        return lastFlightMode;
172
}
173
 
1910 - 174
/*
2099 - 175
 * Get Pitch, Roll, Throttle, Yaw values
1910 - 176
 */
2103 - 177
void RC_periodicTaskAndPRYT(int16_t* PRYT) {
2124 - 178
  RC_process();
2099 - 179
 
2124 - 180
  PRYT[CONTROL_ELEVATOR]   = RCChannel(CH_ELEVATOR)   - rcTrim.trim[CH_ELEVATOR];
181
  PRYT[CONTROL_AILERONS]   = RCChannel(CH_AILERONS)   - rcTrim.trim[CH_AILERONS];
182
  PRYT[CONTROL_RUDDER]     = RCChannel(CH_RUDDER)     - rcTrim.trim[CH_RUDDER];
183
  PRYT[CONTROL_THROTTLE]   = RCChannel(CH_THROTTLE);  // no trim on throttle!
2102 - 184
 
2124 - 185
  debugOut.analog[20] = PRYT[CONTROL_ELEVATOR];
186
  debugOut.analog[21] = PRYT[CONTROL_AILERONS];
187
  debugOut.analog[22] = PRYT[CONTROL_RUDDER];
188
  debugOut.analog[23] = PRYT[CONTROL_THROTTLE];
1910 - 189
}
190
 
191
/*
192
 * Get other channel value
193
 */
194
int16_t RC_getVariable(uint8_t varNum) {
195
  if (varNum < 4)
196
    // 0th variable is 5th channel (1-based) etc.
2116 - 197
    return (RCChannel(varNum + CH_POTS) >> 3) + channelMap.variableOffset;
1910 - 198
  /*
199
   * Let's just say:
2099 - 200
   * The RC variable i is hardwired to channel i, i>=4
1910 - 201
   */
2116 - 202
  return (PPM_in[varNum] >> 3) + channelMap.variableOffset;
1910 - 203
}
204
 
205
uint8_t RC_getSignalQuality(void) {
2099 - 206
  if (RCQuality >= 160)
1910 - 207
    return SIGNAL_GOOD;
2099 - 208
  if (RCQuality >= 140)
1910 - 209
    return SIGNAL_OK;
2099 - 210
  if (RCQuality >= 120)
1910 - 211
    return SIGNAL_BAD;
212
  return SIGNAL_LOST;
213
}
214
 
215
void RC_calibrate(void) {
2122 - 216
  rcTrim.trim[CH_ELEVATOR] = RCChannel(CH_ELEVATOR);
217
  rcTrim.trim[CH_AILERONS] = RCChannel(CH_AILERONS);
218
  rcTrim.trim[CH_RUDDER]   = RCChannel(CH_RUDDER);
219
  rcTrim.trim[CH_THROTTLE] = 0;
1910 - 220
}
2115 - 221
 
2119 - 222
int16_t RC_getZeroThrottle(void) {
2136 - 223
        return TIME(1.0f);
2115 - 224
}
2122 - 225
 
226
void RC_setZeroTrim(void) {
227
  for (uint8_t i=0; i<MAX_CHANNELS; i++) {
228
    rcTrim.trim[i] = 0;
229
  }
230
}