Rev 2125 | Rev 2135 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2125 | Rev 2132 | ||
---|---|---|---|
Line 8... | Line 8... | ||
8 | #include "commands.h" |
8 | #include "commands.h" |
9 | #include "output.h" |
9 | #include "output.h" |
Line 10... | Line 10... | ||
10 | 10 | ||
11 | // The channel array is 0-based! |
11 | // The channel array is 0-based! |
- | 12 | volatile int16_t PPM_in[MAX_CHANNELS]; |
|
- | 13 | volatile uint16_t RC_buffer[MAX_CHANNELS]; |
|
- | 14 | volatile uint8_t inBfrPnt = 0; |
|
12 | volatile int16_t PPM_in[MAX_CHANNELS]; |
15 | |
Line 13... | Line 16... | ||
13 | volatile uint8_t RCQuality; |
16 | volatile uint8_t RCQuality; |
14 | 17 | ||
Line 53... | Line 56... | ||
53 | RCQuality = 0; |
56 | RCQuality = 0; |
Line 54... | Line 57... | ||
54 | 57 | ||
55 | SREG = sreg; |
58 | SREG = sreg; |
Line -... | Line 59... | ||
- | 59 | } |
|
- | 60 | ||
- | 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 | } |
|
56 | } |
74 | } |
57 | 75 | ||
58 | /********************************************************************/ |
76 | /********************************************************************/ |
59 | /* Every time a positive edge is detected at PD6 */ |
77 | /* Every time a positive edge is detected at PD6 */ |
60 | /********************************************************************/ |
78 | /********************************************************************/ |
Line 74... | Line 92... | ||
74 | The minimum duration of all channels at minimum value is 8 * 1 ms = 8 ms. |
92 | The minimum duration of all channels at minimum value is 8 * 1 ms = 8 ms. |
75 | The maximum duration of all channels at maximum value is 8 * 2 ms = 16 ms. |
93 | The maximum duration of all channels at maximum value is 8 * 2 ms = 16 ms. |
76 | The remaining time of (22.5 - 8 ms) ms = 14.5 ms to (22.5 - 16 ms) ms = 6.5 ms is |
94 | The remaining time of (22.5 - 8 ms) ms = 14.5 ms to (22.5 - 16 ms) ms = 6.5 ms is |
77 | the syncronization gap. |
95 | the syncronization gap. |
78 | */ |
96 | */ |
79 | ISR(TIMER1_CAPT_vect) { // typical rate of 1 ms to 2 ms |
- | |
80 | int16_t signal, tmp; |
97 | void RC_process(void) { |
81 | static int16_t index; |
98 | if (RCQuality) RCQuality--; |
82 | static uint16_t oldICR1 = 0; |
- | |
83 | - | ||
84 | // 16bit Input Capture Register ICR1 contains the timer value TCNT1 |
- | |
85 | // at the time the edge was detected |
- | |
86 | - | ||
87 | // calculate the time delay to the previous event time which is stored in oldICR1 |
- | |
88 | // calculatiing the difference of the two uint16_t and converting the result to an int16_t |
- | |
89 | // implicit handles a timer overflow 65535 -> 0 the right way. |
99 | for (uint8_t channel=0; channel<MAX_CHANNELS; channel++) { |
90 | signal = (uint16_t) ICR1 - oldICR1; |
100 | uint16_t signal = RC_buffer[channel]; |
91 | oldICR1 = ICR1; |
- | |
92 | - | ||
93 | //sync gap? (3.5 ms < signal < 25.6 ms) |
- | |
94 | if (signal > TIME(3.5)) { |
101 | if (signal != 0) { |
95 | index = 0; |
- | |
96 | } else { // within the PPM frame |
- | |
97 | if (index < MAX_CHANNELS) { // PPM24 supports 12 channels |
- | |
98 | // check for valid signal length (0.8 ms < signal < 2.2 ms) |
102 | RC_buffer[channel] = 0; // reset to flag value already used. |
99 | if ((signal >= TIME(0.8)) && (signal < TIME(2.2))) { |
103 | if ((signal >= TIME(0.8)) && (signal < TIME(2.2))) { |
100 | // shift signal to zero symmetric range -154 to 159 |
- | |
101 | //signal -= 3750; // theoretical value |
- | |
102 | signal -= (TIME(1.5) - 128 + channelMap.trim-128); // best value with my Futaba in zero trim. |
104 | signal -= (TIME(1.5) - 128 + channelMap.HWTrim); |
103 | // check for stable signal |
- | |
104 | if (abs(signal - PPM_in[index]) < TIME(0.05)) { |
105 | if (abs(signal - PPM_in[channel]) < TIME(0.05)) { |
- | 106 | // With 7 channels and 50 frames/sec, we get 350 channel values/sec. |
|
105 | if (RCQuality < 200) |
107 | if (RCQuality < 200) |
106 | RCQuality += 10; |
108 | RCQuality += 2; |
107 | else |
- | |
108 | RCQuality = 200; |
- | |
109 | } |
109 | } |
110 | // If signal is the same as before +/- 1, just keep it there. Naah lets get rid of this slimy sticy stuff. |
- | |
111 | // if (signal >= PPM_in[index] - 1 && signal <= PPM_in[index] + 1) { |
- | |
112 | // In addition, if the signal is very close to 0, just set it to 0. |
- | |
113 | if (signal >= -1 && signal <= 1) { |
- | |
114 | tmp = 0; |
- | |
115 | //} else { |
- | |
116 | // tmp = PPM_in[index]; |
- | |
117 | // } |
- | |
118 | } else |
- | |
119 | tmp = signal; |
110 | PPM_in[channel] = signal; |
120 | PPM_in[index] = tmp; // update channel value |
- | |
121 | } |
111 | } |
122 | index++; // next channel |
- | |
123 | // demux sum signal for channels 5 to 7 to J3, J4, J5 |
- | |
124 | // TODO: General configurability of this R/C channel forwarding. Or remove it completely - the |
- | |
125 | // channels are usually available at the receiver anyway. |
- | |
126 | // if(index == 5) J3HIGH; else J3LOW; |
- | |
127 | // if(index == 6) J4HIGH; else J4LOW; |
- | |
128 | // if(CPUType != ATMEGA644P) // not used as TXD1 |
- | |
129 | // { |
- | |
130 | // if(index == 7) J5HIGH; else J5LOW; |
- | |
131 | // } |
- | |
132 | } |
112 | } |
133 | } |
113 | } |
134 | } |
114 | } |
Line 135... | Line 115... | ||
135 | 115 | ||
136 | #define RCChannel(dimension) PPM_in[channelMap.channels[dimension]] |
- | |
137 | #define COMMAND_CHANNEL_VERTICAL CH_THROTTLE |
- | |
Line 138... | Line 116... | ||
138 | #define COMMAND_CHANNEL_HORIZONTAL CH_YAW |
116 | #define RCChannel(dimension) PPM_in[channelMap.channels[dimension]] |
139 | 117 | ||
140 | uint8_t getControlModeSwitch(void) { |
118 | uint8_t getControlModeSwitch(void) { |
141 | int16_t channel = RCChannel(CH_MODESWITCH); |
119 | int16_t channel = RCChannel(CH_MODESWITCH); |
Line 158... | Line 136... | ||
158 | } |
136 | } |
Line 159... | Line 137... | ||
159 | 137 | ||
Line 160... | Line 138... | ||
160 | int16_t channel = RCChannel(CH_THROTTLE); |
138 | int16_t channel = RCChannel(CH_THROTTLE); |
- | 139 | ||
- | 140 | if (channel <= -TIME(0.55)) { |
|
161 | 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. |
|
162 | if (channel <= -TIME(0.55)) { |
143 | lastRCCommand = COMMAND_GYROCAL; |
163 | lastRCCommand = COMMAND_GYROCAL; |
144 | else |
164 | debugOut.analog[17] = 1; |
145 | lastRCCommand = COMMAND_RCCAL; |
165 | } else { |
- | |
166 | lastRCCommand = COMMAND_NONE; |
146 | } else { |
167 | debugOut.analog[17] = 0; |
147 | lastRCCommand = COMMAND_NONE; |
168 | } |
148 | } |
Line 169... | Line 149... | ||
169 | return lastRCCommand; |
149 | return lastRCCommand; |
Line 175... | Line 155... | ||
175 | 155 | ||
176 | /* |
156 | /* |
177 | * Get Pitch, Roll, Throttle, Yaw values |
157 | * Get Pitch, Roll, Throttle, Yaw values |
178 | */ |
158 | */ |
179 | void RC_periodicTaskAndPRYT(int16_t* PRYT) { |
- | |
180 | if (RCQuality) { |
159 | void RC_periodicTaskAndPRYT(int16_t* PRYT) { |
- | 160 | RC_process(); |
|
181 | RCQuality--; |
161 | |
182 | PRYT[CONTROL_ELEVATOR] = RCChannel(CH_ELEVATOR); |
162 | PRYT[CONTROL_ELEVATOR] = RCChannel(CH_ELEVATOR) - rcTrim.trim[CH_ELEVATOR]; |
183 | PRYT[CONTROL_AILERONS] = RCChannel(CH_AILERONS); |
163 | PRYT[CONTROL_AILERONS] = RCChannel(CH_AILERONS) - rcTrim.trim[CH_AILERONS]; |
184 | PRYT[CONTROL_RUDDER] = RCChannel(CH_RUDDER); |
164 | PRYT[CONTROL_RUDDER] = RCChannel(CH_RUDDER) - rcTrim.trim[CH_RUDDER]; |
185 | PRYT[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE); |
- | |
186 | } // if RCQuality is no good, we just do nothing. |
165 | PRYT[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE); // no trim on throttle! |
Line 187... | Line 166... | ||
187 | } |
166 | } |
188 | 167 | ||
189 | /* |
168 | /* |
190 | * Get other channel value |
169 | * Get other channel value |
191 | */ |
170 | */ |
192 | int16_t RC_getVariable(uint8_t varNum) { |
171 | int16_t RC_getVariable(uint8_t varNum) { |
193 | if (varNum < 4) |
172 | if (varNum < 4) |
194 | // 0th variable is 5th channel (1-based) etc. |
173 | // 0th variable is 5th channel (1-based) etc. |
195 | return (RCChannel(varNum + CH_POTS) >> 2) + channelMap.variableOffset; |
174 | return (RCChannel(varNum + CH_POTS) >> 3) + channelMap.variableOffset; |
196 | /* |
175 | /* |
197 | * Let's just say: |
176 | * Let's just say: |
198 | * The RC variable i is hardwired to channel i, i>=4 |
177 | * The RC variable i is hardwired to channel i, i>=4 |
199 | */ |
178 | */ |
Line 200... | Line 179... | ||
200 | return (PPM_in[varNum] >> 2) + channelMap.variableOffset; |
179 | return (PPM_in[varNum] >> 3) + channelMap.variableOffset; |
201 | } |
180 | } |
202 | 181 | ||
Line 209... | Line 188... | ||
209 | return SIGNAL_BAD; |
188 | return SIGNAL_BAD; |
210 | return SIGNAL_LOST; |
189 | return SIGNAL_LOST; |
211 | } |
190 | } |
Line 212... | Line 191... | ||
212 | 191 | ||
- | 192 | void RC_calibrate(void) { |
|
- | 193 | rcTrim.trim[CH_ELEVATOR] = RCChannel(CH_ELEVATOR); |
|
- | 194 | rcTrim.trim[CH_AILERONS] = RCChannel(CH_AILERONS); |
|
213 | void RC_calibrate(void) { |
195 | rcTrim.trim[CH_RUDDER] = RCChannel(CH_RUDDER); |
214 | // Do nothing. |
196 | rcTrim.trim[CH_THROTTLE] = 0; |
Line 215... | Line 197... | ||
215 | } |
197 | } |
216 | 198 | ||
217 | int16_t RC_getZeroThrottle() { |
199 | int16_t RC_getZeroThrottle(void) { |
- | 200 | return TIME (-0.5); |
|
- | 201 | } |
|
- | 202 | ||
- | 203 | void RC_setZeroTrim(void) { |
|
- | 204 | for (uint8_t i=0; i<MAX_CHANNELS; i++) { |
|
- | 205 | rcTrim.trim[i] = 0; |