Subversion Repositories FlightCtrl

Rev

Rev 2125 | Rev 2135 | Go to most recent revision | 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)) {
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)) {
2132 - 141
          int16_t aux = RCChannel(COMMAND_CHANNEL_HORIZONTAL);
142
          if (abs(aux) >= TIME(0.3)) // If we pull on the stick, it is gyrocal. Else it is RC cal.
143
                lastRCCommand = COMMAND_GYROCAL;
144
          else
145
                lastRCCommand = COMMAND_RCCAL;
2108 - 146
        } else {
147
          lastRCCommand = COMMAND_NONE;
148
        }
149
        return lastRCCommand;
150
}
151
 
152
uint8_t RC_getArgument(void) {
153
        return lastFlightMode;
154
}
155
 
156
/*
157
 * Get Pitch, Roll, Throttle, Yaw values
158
 */
159
void RC_periodicTaskAndPRYT(int16_t* PRYT) {
2132 - 160
  RC_process();
161
 
162
  PRYT[CONTROL_ELEVATOR]   = RCChannel(CH_ELEVATOR)   - rcTrim.trim[CH_ELEVATOR];
163
  PRYT[CONTROL_AILERONS]   = RCChannel(CH_AILERONS)   - rcTrim.trim[CH_AILERONS];
164
  PRYT[CONTROL_RUDDER]     = RCChannel(CH_RUDDER)     - rcTrim.trim[CH_RUDDER];
165
  PRYT[CONTROL_THROTTLE]   = RCChannel(CH_THROTTLE);  // no trim on throttle!
2108 - 166
}
167
 
168
/*
169
 * Get other channel value
170
 */
171
int16_t RC_getVariable(uint8_t varNum) {
172
  if (varNum < 4)
173
    // 0th variable is 5th channel (1-based) etc.
2132 - 174
    return (RCChannel(varNum + CH_POTS) >> 3) + channelMap.variableOffset;
2108 - 175
  /*
176
   * Let's just say:
177
   * The RC variable i is hardwired to channel i, i>=4
178
   */
2132 - 179
  return (PPM_in[varNum] >> 3) + channelMap.variableOffset;
2108 - 180
}
181
 
182
uint8_t RC_getSignalQuality(void) {
183
  if (RCQuality >= 160)
184
    return SIGNAL_GOOD;
185
  if (RCQuality >= 140)
186
    return SIGNAL_OK;
187
  if (RCQuality >= 120)
188
    return SIGNAL_BAD;
189
  return SIGNAL_LOST;
190
}
191
 
192
void RC_calibrate(void) {
2132 - 193
  rcTrim.trim[CH_ELEVATOR] = RCChannel(CH_ELEVATOR);
194
  rcTrim.trim[CH_AILERONS] = RCChannel(CH_AILERONS);
195
  rcTrim.trim[CH_RUDDER]   = RCChannel(CH_RUDDER);
196
  rcTrim.trim[CH_THROTTLE] = 0;
2108 - 197
}
2115 - 198
 
2132 - 199
int16_t RC_getZeroThrottle(void) {
2115 - 200
        return TIME (-0.5);
201
}
2132 - 202
 
203
void RC_setZeroTrim(void) {
204
  for (uint8_t i=0; i<MAX_CHANNELS; i++) {
205
    rcTrim.trim[i] = 0;
206
  }
207
}