Subversion Repositories FlightCtrl

Rev

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