Subversion Repositories FlightCtrl

Rev

Rev 2099 | Rev 2103 | 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];
2099 - 13
volatile uint8_t RCQuality;
2102 - 14
 
1910 - 15
uint8_t lastRCCommand = COMMAND_NONE;
16
uint8_t commandTimer = 0;
17
 
2102 - 18
uint8_t lastFlightMode = FLIGHT_MODE_NONE;
19
 
1910 - 20
/***************************************************************
21
 *  16bit timer 1 is used to decode the PPM-Signal            
22
 ***************************************************************/
23
void RC_Init(void) {
24
  uint8_t sreg = SREG;
25
 
26
  // disable all interrupts before reconfiguration
27
  cli();
28
 
29
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
2099 - 30
  DDRD &= ~(1<<6);
31
  PORTD |= (1<<PORTD6);
1910 - 32
 
33
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
34
  // set as output
2099 - 35
  DDRD |= (1<<DDD5) | (1<<DDD4) | (1<<DDD3);
1910 - 36
  // low level
2099 - 37
  PORTD &= ~((1<<PORTD5) | (1<<PORTD4) | (1<<PORTD3));
1910 - 38
 
39
  // PD3 can't be used if 2nd UART is activated
40
  // because TXD1 is at that port
41
  if (CPUType != ATMEGA644P) {
2099 - 42
    DDRD |= (1<<PORTD3);
43
    PORTD &= ~(1<<PORTD3);
1910 - 44
  }
45
 
46
  // Timer/Counter1 Control Register A, B, C
47
 
48
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
49
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
50
  // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
51
  // Enable input capture noise cancler (bit: ICNC1=1)
52
  // Trigger on positive edge of the input capture pin (bit: ICES1=1),
2099 - 53
  // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2�s
1910 - 54
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
2099 - 55
  TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10));
1910 - 56
  TCCR1B &= ~((1 << WGM13) | (1 << WGM12) | (1 << CS12));
57
  TCCR1B |= (1 << CS11) | (1 << CS10) | (1 << ICES1) | (1 << ICNC1);
58
  TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
59
 
60
  // Timer/Counter1 Interrupt Mask Register
61
  // Enable Input Capture Interrupt (bit: ICIE1=1)
62
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
63
  // Enable Overflow Interrupt (bit: TOIE1=0)
2099 - 64
  TIMSK1 &= ~((1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1));
65
  TIMSK1 |= (1<<ICIE1);
1910 - 66
 
2099 - 67
  RCQuality = 0;
1910 - 68
 
69
  SREG = sreg;
70
}
71
 
72
/********************************************************************/
73
/*         Every time a positive edge is detected at PD6            */
74
/********************************************************************/
75
/*                               t-Frame
2099 - 76
    <----------------------------------------------------------------------->
77
     ____   ______   _____   ________                ______    sync gap      ____
78
    |    | |      | |     | |        |              |      |                |
79
    |    | |      | |     | |        |              |      |                |
1910 - 80
 ___|    |_|      |_|     |_|        |_.............|      |________________|
2099 - 81
    <-----><-------><------><-----------            <------>                <---
1910 - 82
 t0       t1      t2       t4                     tn                     t0
83
 
84
 The PPM-Frame length is 22.5 ms.
85
 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
86
 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
2099 - 87
 The maximum time delay of two events coding a channel is ( 1.7 + 0.3) ms = 2 ms.
1910 - 88
 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
89
 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
90
 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
91
 the syncronization gap.
92
 */
2099 - 93
ISR(TIMER1_CAPT_vect) { // typical rate of 1 ms to 2 ms
94
  int16_t signal = 0, tmp;
1910 - 95
  static int16_t index;
96
  static uint16_t oldICR1 = 0;
97
 
98
  // 16bit Input Capture Register ICR1 contains the timer value TCNT1
99
  // at the time the edge was detected
100
 
101
  // calculate the time delay to the previous event time which is stored in oldICR1
102
  // calculatiing the difference of the two uint16_t and converting the result to an int16_t
103
  // implicit handles a timer overflow 65535 -> 0 the right way.
104
  signal = (uint16_t) ICR1 - oldICR1;
105
  oldICR1 = ICR1;
106
 
107
  //sync gap? (3.52 ms < signal < 25.6 ms)
108
  if ((signal > 1100) && (signal < 8000)) {
2099 - 109
    index = 0;
1910 - 110
  } else { // within the PPM frame
2099 - 111
    if (index < MAX_CHANNELS) { // PPM24 supports 12 channels
1910 - 112
      // check for valid signal length (0.8 ms < signal < 2.1984 ms)
2099 - 113
      // signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
1910 - 114
      if ((signal > 250) && (signal < 687)) {
115
        // shift signal to zero symmetric range  -154 to 159
2099 - 116
        signal -= 475; // offset of 1.4912 ms ??? (469 * 3.2us = 1.5008 ms)
117
        // check for stable signal
1910 - 118
        if (abs(signal - PPM_in[index]) < 6) {
2099 - 119
          if (RCQuality < 200)
120
            RCQuality += 10;
1910 - 121
          else
2099 - 122
            RCQuality = 200;
1910 - 123
        }
2099 - 124
        // If signal is the same as before +/- 1, just keep it there. Naah lets get rid of this slimy sticy stuff.
125
        // if (signal >= PPM_in[index] - 1 && signal <= PPM_in[index] + 1) {
126
          // In addition, if the signal is very close to 0, just set it to 0.
127
        if (signal >= -1 && signal <= 1) {
128
          tmp = 0;
129
        //} else {
130
        //  tmp = PPM_in[index];
131
        //  }
132
        } else
133
          tmp = signal;
134
        PPM_in[index] = tmp; // update channel value
1910 - 135
      }
136
      index++; // next channel
2099 - 137
      // demux sum signal for channels 5 to 7 to J3, J4, J5
138
      // TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
139
      // channels are usually available at the receiver anyway.
140
      // if(index == 5) J3HIGH; else J3LOW;
141
      // if(index == 6) J4HIGH; else J4LOW;
142
      // if(CPUType != ATMEGA644P) // not used as TXD1
143
      //  {
144
      //    if(index == 7) J5HIGH; else J5LOW;
145
      //  }
1910 - 146
    }
147
  }
148
}
149
 
2099 - 150
#define RCChannel(dimension) PPM_in[channelMap.channels[dimension]]
151
#define COMMAND_THRESHOLD 85
152
#define COMMAND_CHANNEL_VERTICAL CH_THROTTLE
153
#define COMMAND_CHANNEL_HORIZONTAL CH_YAW
1910 - 154
 
2102 - 155
#define RC_SCALING 4
156
 
157
uint8_t getControlModeSwitch() {
158
        int16_t channel = RCChannel(CH_MODESWITCH) + POT_OFFSET;
159
        uint8_t flightMode = channel < 256/3 ? FLIGHT_MODE_MANUAL :
160
                (channel > 256*2/3 ? FLIGHT_MODE_ANGLES : FLIGHT_MODE_RATE);
161
        return flightMode;
162
}
163
 
164
// Gyro calibration is performed as.... well mode switch with no throttle and no airspeed would be nice.
165
// Maybe simply: Very very low throttle.
166
// Throttle xlow for COMMAND_TIMER: GYROCAL (once).
167
// mode switched: CHMOD
168
 
169
uint8_t RC_getCommand(void) {
170
        uint8_t flightMode = getControlModeSwitch();
171
 
172
        if (lastFlightMode != flightMode) {
173
                lastFlightMode = flightMode;
174
                lastRCCommand = COMMAND_CHMOD;
175
                return lastRCCommand;
176
        }
177
 
178
        int16_t channel = RCChannel(CH_MODESWITCH) + POT_OFFSET;
179
        if (channel <= -32) { // <= 900 us
180
                if (commandTimer == COMMAND_TIMER) {
181
                        lastRCCommand = COMMAND_GYROCAL;
182
                }
183
                if (commandTimer <= COMMAND_TIMER) {
184
                        commandTimer++;
185
                }
186
        } else commandTimer = 0;
187
        return lastRCCommand;
188
}
189
 
190
uint8_t RC_getArgument(void) {
191
        return lastFlightMode;
192
}
193
 
1910 - 194
/*
2099 - 195
 * Get Pitch, Roll, Throttle, Yaw values
1910 - 196
 */
2099 - 197
void RC_periodicTaskAndPRTY(int16_t* PRTY) {
198
  if (RCQuality) {
199
    RCQuality--;
2102 - 200
    PRTY[CONTROL_ELEVATOR]   = RCChannel(CH_ELEVATOR) * RC_SCALING;
201
    PRTY[CONTROL_AILERONS]   = RCChannel(CH_AILERONS) * RC_SCALING;
202
    PRTY[CONTROL_THROTTLE]   = RCChannel(CH_THROTTLE) * RC_SCALING;
203
    PRTY[CONTROL_RUDDER]     = RCChannel(CH_RUDDER)   * RC_SCALING;
2099 - 204
 
2102 - 205
    debugOut.analog[16] = PRTY[CONTROL_ELEVATOR];
206
    debugOut.analog[17] = PRTY[CONTROL_THROTTLE];
207
 
2099 - 208
    uint8_t command = COMMAND_NONE; //RC_getStickCommand();
209
    if (lastRCCommand == command) {
210
      // Keep timer from overrunning.
211
      if (commandTimer < COMMAND_TIMER)
212
        commandTimer++;
213
    } else {
214
      // There was a change.
215
      lastRCCommand = command;
216
      commandTimer = 0;
1910 - 217
    }
2099 - 218
  } // if RCQuality is no good, we just do nothing.
1910 - 219
}
220
 
221
/*
222
 * Get other channel value
223
 */
224
int16_t RC_getVariable(uint8_t varNum) {
225
  if (varNum < 4)
226
    // 0th variable is 5th channel (1-based) etc.
2099 - 227
    return RCChannel(varNum + CH_POTS) + POT_OFFSET;
1910 - 228
  /*
229
   * Let's just say:
2099 - 230
   * The RC variable i is hardwired to channel i, i>=4
1910 - 231
   */
2099 - 232
  return PPM_in[varNum] + POT_OFFSET;
1910 - 233
}
234
 
235
uint8_t RC_getSignalQuality(void) {
2099 - 236
  if (RCQuality >= 160)
1910 - 237
    return SIGNAL_GOOD;
2099 - 238
  if (RCQuality >= 140)
1910 - 239
    return SIGNAL_OK;
2099 - 240
  if (RCQuality >= 120)
1910 - 241
    return SIGNAL_BAD;
242
  return SIGNAL_LOST;
243
}
244
 
245
/*
246
 * To should fired only when the right stick is in the center position.
247
 * This will cause the value of pitch and roll stick to be adjusted
248
 * to zero (not just to near zero, as per the assumption in rc.c
249
 * about the rc signal. I had values about 50..70 with a Futaba
250
 * R617 receiver.) This calibration is not strictly necessary, but
251
 * for control logic that depends on the exact (non)center position
252
 * of a stick, it may be useful.
253
 */
254
void RC_calibrate(void) {
255
  // Do nothing.
256
}