Subversion Repositories FlightCtrl

Rev

Rev 2141 | Details | Compare with Previous | Last modification | View Log | RSS feed

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