Subversion Repositories FlightCtrl

Rev

Rev 2099 | Go to most recent revision | Details | 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 "uart0.h"
7
#include "controlMixer.h"
8
#include "configuration.h"
9
#include "commands.h"
10
 
11
// The channel array is 1-based. The 0th entry is not used.
12
volatile int16_t PPM_in[MAX_CHANNELS];
13
volatile uint8_t NewPpmData = 1;
14
volatile int16_t RC_Quality = 0;
15
int16_t RC_PRTY[4];
16
uint8_t lastRCCommand = COMMAND_NONE;
17
uint8_t commandTimer = 0;
18
 
19
// Useless. Just trim on the R/C instead.
20
// int16_t stickOffsetPitch = 0, stickOffsetRoll = 0;
21
 
22
/***************************************************************
23
 *  16bit timer 1 is used to decode the PPM-Signal            
24
 ***************************************************************/
25
void RC_Init(void) {
26
  uint8_t sreg = SREG;
27
 
28
  // disable all interrupts before reconfiguration
29
  cli();
30
 
31
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
32
  DDRD &= ~(1 << DDD6);
33
  PORTD |= (1 << PORTD6);
34
 
35
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
36
  // set as output
37
  DDRD |= (1 << DDD5) | (1 << DDD4) | (1 << DDD3);
38
  // low level
39
  PORTD &= ~((1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3));
40
 
41
  // PD3 can't be used if 2nd UART is activated
42
  // because TXD1 is at that port
43
  if (CPUType != ATMEGA644P) {
44
    DDRD |= (1 << PORTD3);
45
    PORTD &= ~(1 << PORTD3);
46
  }
47
 
48
  // Timer/Counter1 Control Register A, B, C
49
 
50
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
51
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
52
  // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
53
  // Enable input capture noise cancler (bit: ICNC1=1)
54
  // Trigger on positive edge of the input capture pin (bit: ICES1=1),
55
  // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2µs
56
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
57
  TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0)
58
      | (1 << WGM11) | (1 << WGM10));
59
  TCCR1B &= ~((1 << WGM13) | (1 << WGM12) | (1 << CS12));
60
  TCCR1B |= (1 << CS11) | (1 << CS10) | (1 << ICES1) | (1 << ICNC1);
61
  TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
62
 
63
  // Timer/Counter1 Interrupt Mask Register
64
 
65
  // Enable Input Capture Interrupt (bit: ICIE1=1)
66
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
67
  // Enable Overflow Interrupt (bit: TOIE1=0)
68
  TIMSK1 &= ~((1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1));
69
  TIMSK1 |= (1 << ICIE1);
70
 
71
  RC_Quality = 0;
72
 
73
  SREG = sreg;
74
}
75
 
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 chanel 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
 */
97
ISR(TIMER1_CAPT_vect)
98
{ // typical rate of 1 ms to 2 ms
99
  int16_t signal = 0;
100
  static int16_t index;
101
  static uint16_t oldICR1 = 0;
102
 
103
  // 16bit Input Capture Register ICR1 contains the timer value TCNT1
104
  // at the time the edge was detected
105
 
106
  // calculate the time delay to the previous event time which is stored in oldICR1
107
  // calculatiing the difference of the two uint16_t and converting the result to an int16_t
108
  // implicit handles a timer overflow 65535 -> 0 the right way.
109
  signal = (uint16_t) ICR1 - oldICR1;
110
  oldICR1 = ICR1;
111
 
112
  //sync gap? (3.52 ms < signal < 25.6 ms)
113
  if ((signal > 1100) && (signal < 8000)) {
114
    // if a sync gap happens and there where at least 4 channels decoded before
115
    // then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
116
    if (index >= 4) {
117
      NewPpmData = 0; // Null means NewData for the first 4 channels
118
    }
119
    // synchronize channel index
120
    index = 1;
121
  } else { // within the PPM frame
122
    if (index < MAX_CHANNELS - 1) { // PPM24 supports 12 channels
123
      // check for valid signal length (0.8 ms < signal < 2.1984 ms)
124
      // signal range is from 1.0ms/3.2us = 312.5 to 2.0ms/3.2us = 625
125
      if ((signal > 250) && (signal < 687)) {
126
        // shift signal to zero symmetric range  -154 to 159
127
        signal -= 475; // offset of 1.4912 ms ??? (469 * 3.2µs = 1.5008 ms)
128
        // Signal is now in the +/- 156 range (nominally).
129
        if (abs(signal - PPM_in[index]) < 6) {
130
          if (RC_Quality < 200)
131
            RC_Quality += 10;
132
          else
133
            RC_Quality = 200;
134
        }
135
        PPM_in[index] = signal; // update channel value
136
      }
137
      index++; // next channel
138
    }
139
  }
140
}
141
 
142
#define RCChannel(dimension) PPM_in[staticParams.ChannelAssignment[dimension]]
143
 
144
/*
145
 * This must be called (as the only thing) for each control loop cycle (488 Hz).
146
 */
147
void RC_update() {
148
  if (RC_Quality) {
149
    RC_Quality--;
150
    if (NewPpmData-- == 0) {
151
        RC_PRTY[CONTROL_ELEVATOR] = RCChannel(CH_ELEVATOR) * staticParams.StickElevatorP * 2/ 10;
152
        RC_PRTY[CONTROL_AILERONS] = RCChannel(CH_AILERONS) * staticParams.StickAileronsP * 2 / 10;
153
        RC_PRTY[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE) * 2 + 310;
154
      if (RC_PRTY[CONTROL_THROTTLE] < 0)
155
        RC_PRTY[CONTROL_THROTTLE] = 0; // Throttle is non negative.
156
        RC_PRTY[CONTROL_RUDDER] = RCChannel(CH_RUDDER) * staticParams.StickRudderP * 2 / 10;
157
    }
158
  } else { // Bad signal
159
    RC_PRTY[CONTROL_ELEVATOR] = RC_PRTY[CONTROL_AILERONS] = RC_PRTY[CONTROL_THROTTLE]
160
        = RC_PRTY[CONTROL_RUDDER] = 0;
161
  }
162
}
163
 
164
/*
165
 * Get Pitch, Roll, Throttle, Yaw values
166
 */
167
int16_t* RC_getEATR(void) {
168
  return RC_PRTY;
169
}
170
 
171
/*
172
 * Get other channel value
173
 */
174
int16_t RC_getVariable(uint8_t varNum) {
175
  if (varNum < 4)
176
    // 0th variable is 5th channel (1-based) etc.
177
    return RCChannel(varNum + 4) + POT_OFFSET;
178
  /*
179
   * Let's just say:
180
   * The RC variable 4 is hardwired to channel 5
181
   * The RC variable 5 is hardwired to channel 6
182
   * The RC variable 6 is hardwired to channel 7
183
   * The RC variable 7 is hardwired to channel 8
184
   * Alternatively, one could bind them to channel (4 + varNum) - or whatever...
185
   */
186
  return PPM_in[varNum + 1] + POT_OFFSET;
187
}
188
 
189
uint8_t RC_getSignalQuality(void) {
190
  if (RC_Quality >= 160)
191
    return SIGNAL_GOOD;
192
  if (RC_Quality >= 140)
193
    return SIGNAL_OK;
194
  if (RC_Quality >= 120)
195
    return SIGNAL_BAD;
196
  return SIGNAL_LOST;
197
}
198
 
199
/*
200
 * To should fired only when the right stick is in the center position.
201
 * This will cause the value of pitch and roll stick to be adjusted
202
 * to zero (not just to near zero, as per the assumption in rc.c
203
 * about the rc signal. I had values about 50..70 with a Futaba
204
 * R617 receiver.) This calibration is not strictly necessary, but
205
 * for control logic that depends on the exact (non)center position
206
 * of a stick, it may be useful.
207
 */
208
void RC_calibrate(void) {
209
  // Do nothing.
210
}
211
 
212
/*
213
 if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
214
 // In HH, it s OK to trim the R/C. The effect should not be conteracted here.
215
 stickOffsetPitch = stickOffsetRoll = 0;
216
 } else {
217
 stickOffsetPitch = RCChannel(CH_PITCH) * staticParams.StickP;
218
 stickOffsetRoll = RCChannel(CH_ROLL)   * staticParams.StickP;
219
 }
220
 }
221
 */
222
 
223
uint8_t RC_getCommand(void) {
224
  // Noy impplemented - not from RC at least.
225
  return COMMAND_NONE;
226
}
227
 
228
/*
229
 * Command arguments on R/C:
230
 * 2--3--4
231
 * |     |  +
232
 * 1  0  5  ^ 0
233
 * |     |  |  
234
 * 8--7--6
235
 *    
236
 * + <--
237
 *    0
238
 *
239
 * Not in any of these positions: 0
240
 */
241
uint8_t RC_getArgument(void) {
242
  return 0;
243
}
244
 
245
uint8_t RC_testCompassCalState(void) {
246
  return 0;
247
}
248
/*
249
 * Abstract controls are not used at the moment.
250
 t_control rc_control = {
251
 RC_getPitch,
252
 RC_getRoll,
253
 RC_getYaw,
254
 RC_getThrottle,
255
 RC_getSignalQuality,
256
 RC_calibrate
257
 };
258
 */