Rev 2141 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2141 | Rev 2142 | ||
---|---|---|---|
1 | #include <stdlib.h> |
1 | #include <stdlib.h> |
2 | #include <avr/io.h> |
2 | #include <avr/io.h> |
3 | #include <avr/interrupt.h> |
3 | #include <avr/interrupt.h> |
4 | 4 | ||
5 | #include "rc.h" |
5 | #include "rc.h" |
6 | #include "controlMixer.h" |
6 | #include "controlMixer.h" |
7 | #include "configuration.h" |
7 | #include "configuration.h" |
8 | #include "commands.h" |
8 | #include "commands.h" |
9 | #include "output.h" |
9 | #include "output.h" |
10 | 10 | ||
11 | // The channel array is 0-based! |
11 | // The channel array is 0-based! |
12 | volatile int16_t PPM_in[MAX_CHANNELS]; |
12 | volatile int16_t PPM_in[MAX_CHANNELS]; |
13 | volatile uint16_t RC_buffer[MAX_CHANNELS]; |
13 | volatile uint16_t RC_buffer[MAX_CHANNELS]; |
14 | volatile uint8_t inBfrPnt = 0; |
14 | volatile uint8_t inBfrPnt = 0; |
15 | 15 | ||
16 | volatile uint8_t RCQuality; |
16 | volatile uint8_t RCQuality; |
17 | 17 | ||
18 | uint8_t lastRCCommand = COMMAND_NONE; |
18 | uint8_t lastRCCommand = COMMAND_NONE; |
19 | uint8_t lastFlightMode = FLIGHT_MODE_NONE; |
19 | uint8_t lastFlightMode = FLIGHT_MODE_NONE; |
20 | 20 | ||
21 | #define TIME(s) ((int16_t)(((long)F_CPU/(long)8000)*(float)s)) |
21 | #define TIME(s) ((int16_t)(((long)F_CPU/(long)8000)*(float)s)) |
22 | 22 | ||
23 | /*************************************************************** |
23 | /*************************************************************** |
24 | * 16bit timer 1 is used to decode the PPM-Signal |
24 | * 16bit timer 1 is used to decode the PPM-Signal |
25 | ***************************************************************/ |
25 | ***************************************************************/ |
26 | void RC_Init(void) { |
26 | void RC_Init(void) { |
27 | uint8_t sreg = SREG; |
27 | uint8_t sreg = SREG; |
28 | 28 | ||
29 | // disable all interrupts before reconfiguration |
29 | // disable all interrupts before reconfiguration |
30 | cli(); |
30 | cli(); |
31 | 31 | ||
32 | // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1 |
32 | // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1 |
33 | DDRB &= ~(1<<0); |
33 | DDRB &= ~(1<<0); |
34 | PORTB |= (1<<PORTB0); |
34 | PORTB |= (1<<PORTB0); |
35 | 35 | ||
36 | // Timer/Counter1 Control Register A, B, C |
36 | // Timer/Counter1 Control Register A, B, C |
37 | // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0) |
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) |
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) |
39 | // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1) |
40 | // Enable input capture noise cancler (bit: ICNC1=1) |
40 | // Enable input capture noise cancler (bit: ICNC1=1) |
41 | // Trigger on positive edge of the input capture pin (bit: ICES1=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 |
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. |
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)); |
44 | TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10)); |
45 | TCCR1B &= ~((1 << WGM13) | (1 << WGM12) | (1 << CS12)); |
45 | TCCR1B &= ~((1 << WGM13) | (1 << WGM12) | (1 << CS12)); |
46 | TCCR1B |= (1 << CS11) | (1 << ICES1) | (1 << ICNC1); |
46 | TCCR1B |= (1 << CS11) | (1 << ICES1) | (1 << ICNC1); |
47 | TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B)); |
47 | TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B)); |
48 | 48 | ||
49 | // Timer/Counter1 Interrupt Mask Register |
49 | // Timer/Counter1 Interrupt Mask Register |
50 | // Enable Input Capture Interrupt (bit: ICIE1=1) |
50 | // Enable Input Capture Interrupt (bit: ICIE1=1) |
51 | // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0) |
51 | // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0) |
52 | // Enable Overflow Interrupt (bit: TOIE1=0) |
52 | // Enable Overflow Interrupt (bit: TOIE1=0) |
53 | TIMSK1 &= ~((1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1)); |
53 | TIMSK1 &= ~((1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1)); |
54 | TIMSK1 |= (1<<ICIE1); |
54 | TIMSK1 |= (1<<ICIE1); |
55 | 55 | ||
56 | RCQuality = 0; |
56 | RCQuality = 0; |
57 | 57 | ||
58 | SREG = sreg; |
58 | SREG = sreg; |
59 | } |
59 | } |
60 | 60 | ||
61 | /* |
61 | /* |
62 | * This new and much faster interrupt handler should reduce servo jolts. |
62 | * This new and much faster interrupt handler should reduce servo jolts. |
63 | */ |
63 | */ |
64 | ISR(TIMER1_CAPT_vect) { |
64 | ISR(TIMER1_CAPT_vect) { |
65 | static uint16_t oldICR1 = 0; |
65 | static uint16_t oldICR1 = 0; |
66 | uint16_t signal = (uint16_t)ICR1 - oldICR1; |
66 | uint16_t signal = (uint16_t)ICR1 - oldICR1; |
67 | oldICR1 = ICR1; |
67 | oldICR1 = ICR1; |
68 | //sync gap? (3.5 ms < signal < 25.6 ms) |
68 | //sync gap? (3.5 ms < signal < 25.6 ms) |
69 | if (signal > TIME(3.5)) { |
69 | if (signal > TIME(3.5)) { |
70 | inBfrPnt = 0; |
70 | inBfrPnt = 0; |
71 | } else if (inBfrPnt<MAX_CHANNELS) { |
71 | } else if (inBfrPnt<MAX_CHANNELS) { |
72 | RC_buffer[inBfrPnt++] = signal; |
72 | RC_buffer[inBfrPnt++] = signal; |
73 | } |
73 | } |
74 | } |
74 | } |
75 | 75 | ||
76 | /********************************************************************/ |
76 | /********************************************************************/ |
77 | /* Every time a positive edge is detected at PD6 */ |
77 | /* Every time a positive edge is detected at PD6 */ |
78 | /********************************************************************/ |
78 | /********************************************************************/ |
79 | /* t-Frame |
79 | /* t-Frame |
80 | <-----------------------------------------------------------------------> |
80 | <-----------------------------------------------------------------------> |
81 | ____ ______ _____ ________ ______ sync gap ____ |
81 | ____ ______ _____ ________ ______ sync gap ____ |
82 | | | | | | | | | | | | |
82 | | | | | | | | | | | | |
83 | | | | | | | | | | | | |
83 | | | | | | | | | | | | |
84 | ___| |_| |_| |_| |_.............| |________________| |
84 | ___| |_| |_| |_| |_.............| |________________| |
85 | <-----><-------><------><----------- <------> <--- |
85 | <-----><-------><------><----------- <------> <--- |
86 | t0 t1 t2 t4 tn t0 |
86 | t0 t1 t2 t4 tn t0 |
87 | 87 | ||
88 | The PPM-Frame length is 22.5 ms. |
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. |
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. |
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. |
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. |
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. |
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 |
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. |
95 | the syncronization gap. |
96 | */ |
96 | */ |
97 | void RC_process(void) { |
97 | void RC_process(void) { |
98 | if (RCQuality) RCQuality--; |
98 | if (RCQuality) RCQuality--; |
99 | for (uint8_t channel=0; channel<MAX_CHANNELS; channel++) { |
99 | for (uint8_t channel=0; channel<MAX_CHANNELS; channel++) { |
100 | uint16_t signal = RC_buffer[channel]; |
100 | uint16_t signal = RC_buffer[channel]; |
101 | if (signal != 0) { |
101 | if (signal != 0) { |
102 | RC_buffer[channel] = 0; // reset to flag value already used. |
102 | RC_buffer[channel] = 0; // reset to flag value already used. |
103 | if ((signal >= TIME(0.8)) && (signal < TIME(2.2))) { |
103 | if ((signal >= TIME(0.8)) && (signal < TIME(2.2))) { |
104 | signal -= (TIME(1.5) - 128 + channelMap.HWTrim); |
104 | signal -= (TIME(1.5) - 128 + channelMap.HWTrim); |
105 | if (abs(signal - PPM_in[channel]) < TIME(0.05)) { |
105 | if (abs(signal - PPM_in[channel]) < TIME(0.05)) { |
106 | // With 7 channels and 50 frames/sec, weget 350 channel values/sec. |
106 | // With 7 channels and 50 frames/sec, we get 350 channel values/sec. |
107 | if (RCQuality < 200) |
107 | if (RCQuality < 200) |
108 | RCQuality += 2; |
108 | RCQuality += 2; |
109 | } |
109 | } |
110 | PPM_in[channel] = signal; |
110 | PPM_in[channel] = signal; |
111 | } |
111 | } |
112 | } |
112 | } |
113 | } |
113 | } |
114 | } |
114 | } |
115 | 115 | ||
116 | #define RCChannel(dimension) PPM_in[channelMap.channels[dimension]] |
116 | #define RCChannel(dimension) PPM_in[channelMap.channels[dimension]] |
117 | 117 | ||
118 | uint8_t getControlModeSwitch(void) { |
118 | uint8_t getControlModeSwitch(void) { |
119 | int16_t channel = RCChannel(CH_MODESWITCH); |
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); |
120 | uint8_t flightMode = channel < -TIME(0.17) ? FLIGHT_MODE_MANUAL : (channel > TIME(0.17) ? FLIGHT_MODE_ANGLES : FLIGHT_MODE_RATE); |
121 | return flightMode; |
121 | return flightMode; |
122 | } |
122 | } |
123 | 123 | ||
124 | // Gyro calibration is performed as.... well mode switch with no throttle and no airspeed would be nice. |
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. |
125 | // Maybe simply: Very very low throttle. |
126 | // Throttle xlow for COMMAND_TIMER: GYROCAL (once). |
126 | // Throttle xlow for COMMAND_TIMER: GYROCAL (once). |
127 | // mode switched: CHMOD |
127 | // mode switched: CHMOD |
128 | 128 | ||
129 | uint8_t RC_getCommand(void) { |
129 | uint8_t RC_getCommand(void) { |
130 | uint8_t flightMode = getControlModeSwitch(); |
130 | uint8_t flightMode = getControlModeSwitch(); |
131 | 131 | ||
132 | if (lastFlightMode != flightMode) { |
132 | if (lastFlightMode != flightMode) { |
133 | lastFlightMode = flightMode; |
133 | lastFlightMode = flightMode; |
134 | lastRCCommand = COMMAND_CHMOD; |
134 | lastRCCommand = COMMAND_CHMOD; |
135 | return lastRCCommand; |
135 | return lastRCCommand; |
136 | } |
136 | } |
137 | 137 | ||
138 | int16_t channel = RCChannel(CH_THROTTLE); |
138 | int16_t channel = RCChannel(CH_THROTTLE); |
139 | 139 | ||
140 | if (channel <= -TIME(0.55)) { |
140 | if (channel <= -TIME(0.55)) { |
- | 141 | debugOut.analog[17] = 1; |
|
141 | int16_t aux = RCChannel(COMMAND_CHANNEL_HORIZONTAL); |
142 | 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 | 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 | lastRCCommand = COMMAND_GYROCAL; |
144 | else |
145 | else |
145 | lastRCCommand = COMMAND_RCCAL; |
146 | lastRCCommand = COMMAND_RCCAL; |
146 | } else { |
147 | } else { |
- | 148 | debugOut.analog[17] = 0; |
|
147 | lastRCCommand = COMMAND_NONE; |
149 | lastRCCommand = COMMAND_NONE; |
148 | } |
150 | } |
149 | return lastRCCommand; |
151 | return lastRCCommand; |
150 | } |
152 | } |
151 | 153 | ||
152 | uint8_t RC_getArgument(void) { |
154 | uint8_t RC_getArgument(void) { |
153 | return lastFlightMode; |
155 | return lastFlightMode; |
154 | } |
156 | } |
155 | 157 | ||
156 | /* |
158 | /* |
157 | * Get Pitch, Roll, Throttle, Yaw values |
159 | * Get Pitch, Roll, Throttle, Yaw values |
158 | */ |
160 | */ |
159 | void RC_periodicTaskAndPRYT(int16_t* PRYT) { |
161 | void RC_periodicTaskAndPRYT(int16_t* PRYT) { |
160 | RC_process(); |
162 | RC_process(); |
161 | 163 | ||
162 | PRYT[CONTROL_ELEVATOR] = RCChannel(CH_ELEVATOR) - rcTrim.trim[CH_ELEVATOR]; |
164 | PRYT[CONTROL_ELEVATOR] = RCChannel(CH_ELEVATOR) - rcTrim.trim[CH_ELEVATOR]; |
163 | PRYT[CONTROL_AILERONS] = RCChannel(CH_AILERONS) - rcTrim.trim[CH_AILERONS]; |
165 | PRYT[CONTROL_AILERONS] = RCChannel(CH_AILERONS) - rcTrim.trim[CH_AILERONS]; |
164 | PRYT[CONTROL_RUDDER] = RCChannel(CH_RUDDER) - rcTrim.trim[CH_RUDDER]; |
166 | PRYT[CONTROL_RUDDER] = RCChannel(CH_RUDDER) - rcTrim.trim[CH_RUDDER]; |
165 | PRYT[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE); // no trim on throttle! |
167 | PRYT[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE); // no trim on throttle! |
166 | 168 | ||
167 | debugOut.analog[20] = PRYT[CONTROL_ELEVATOR]; |
169 | debugOut.analog[20] = PRYT[CONTROL_ELEVATOR]; |
168 | debugOut.analog[21] = PRYT[CONTROL_AILERONS]; |
170 | debugOut.analog[21] = PRYT[CONTROL_AILERONS]; |
169 | debugOut.analog[22] = PRYT[CONTROL_RUDDER]; |
171 | debugOut.analog[22] = PRYT[CONTROL_RUDDER]; |
170 | debugOut.analog[23] = PRYT[CONTROL_THROTTLE]; |
172 | debugOut.analog[23] = PRYT[CONTROL_THROTTLE]; |
171 | } |
173 | } |
172 | 174 | ||
173 | /* |
175 | /* |
174 | * Get other channel value |
176 | * Get other channel value |
175 | */ |
177 | */ |
176 | int16_t RC_getVariable(uint8_t varNum) { |
178 | int16_t RC_getVariable(uint8_t varNum) { |
177 | if (varNum < 4) { |
179 | if (varNum < 4) { |
178 | // 0th variable is 5th channel (1-based) etc. |
180 | // 0th variable is 5th channel (1-based) etc. |
179 | int16_t result = (RCChannel(varNum + CH_POTS) / 6) + channelMap.variableOffset; |
181 | int16_t result = (RCChannel(varNum + CH_POTS) / 6) + channelMap.variableOffset; |
180 | return result; |
182 | return result; |
181 | } |
183 | } |
182 | /* |
184 | /* |
183 | * Let's just say: |
185 | * Let's just say: |
184 | * The RC variable i is hardwired to channel i, i>=4 |
186 | * The RC variable i is hardwired to channel i, i>=4 |
185 | */ |
187 | */ |
186 | return (PPM_in[varNum] / 6) + channelMap.variableOffset; |
188 | return (PPM_in[varNum] / 6) + channelMap.variableOffset; |
187 | } |
189 | } |
188 | 190 | ||
189 | uint8_t RC_getSignalQuality(void) { |
191 | uint8_t RC_getSignalQuality(void) { |
190 | if (RCQuality >= 160) |
192 | if (RCQuality >= 160) |
191 | return SIGNAL_GOOD; |
193 | return SIGNAL_GOOD; |
192 | if (RCQuality >= 140) |
194 | if (RCQuality >= 140) |
193 | return SIGNAL_OK; |
195 | return SIGNAL_OK; |
194 | if (RCQuality >= 120) |
196 | if (RCQuality >= 120) |
195 | return SIGNAL_BAD; |
197 | return SIGNAL_BAD; |
196 | return SIGNAL_LOST; |
198 | return SIGNAL_LOST; |
197 | } |
199 | } |
198 | 200 | ||
199 | void RC_calibrate(void) { |
201 | void RC_calibrate(void) { |
200 | rcTrim.trim[CH_ELEVATOR] = RCChannel(CH_ELEVATOR); |
202 | rcTrim.trim[CH_ELEVATOR] = RCChannel(CH_ELEVATOR); |
201 | rcTrim.trim[CH_AILERONS] = RCChannel(CH_AILERONS); |
203 | rcTrim.trim[CH_AILERONS] = RCChannel(CH_AILERONS); |
202 | rcTrim.trim[CH_RUDDER] = RCChannel(CH_RUDDER); |
204 | rcTrim.trim[CH_RUDDER] = RCChannel(CH_RUDDER); |
203 | rcTrim.trim[CH_THROTTLE] = 0; |
205 | rcTrim.trim[CH_THROTTLE] = 0; |
204 | } |
206 | } |
205 | 207 | ||
206 | int16_t RC_getZeroThrottle(void) { |
208 | int16_t RC_getZeroThrottle(void) { |
207 | return TIME (0.95f); |
209 | return TIME (1.0f); |
208 | } |
210 | } |
209 | 211 | ||
210 | void RC_setZeroTrim(void) { |
212 | void RC_setZeroTrim(void) { |
211 | for (uint8_t i=0; i<MAX_CHANNELS; i++) { |
213 | for (uint8_t i=0; i<MAX_CHANNELS; i++) { |
212 | rcTrim.trim[i] = 0; |
214 | rcTrim.trim[i] = 0; |
213 | } |
215 | } |
214 | } |
216 | } |
215 | 217 |