Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
139 jacques 1
/*------------------------------------------------------------------------------
2
**                                                                            **
3
** Ident        : main.c                                                      **
4
** Project      : MX12 2 (3) ppm channel expander                             **
5
** Author       : Jacques Wanders                                             **
6
** Description  : main module                                                 **
7
** Copyright (c): 05.2008 Jacques Wanders                                     **
8
** modified     : 05.2008 Heinrich Fischer for use with WinAVR                **
9
**                                                                            **
10
**----------------------------------------------------------------------------**
11
** Release      : v1.0 initial release                                        **
12
** Date         : 13-05-2008                                                  **
13
**----------------------------------------------------------------------------**
14
** Release      : v1.1                                                        **
15
** Date         : 13-05-2008                                                  **
16
** Notes        : Added Channel 9                                             **
17
**----------------------------------------------------------------------------**
18
** Release      : v1.2                                                        **
19
** Date         : 22-05-2008                                                  **
20
** Notes        : Modified time definitions for FORCE_LOW_END_FRAME           **
21
**                and MIN_SYNC_TIME to avoid lost pulse groups                **
22
**----------------------------------------------------------------------------**
23
** Release      : v1.2sp                                                      **
24
** Date         : 06-10-2008                                                  **
25
** Notes        : Special version, with a total of 8 channels.                **
26
**                original 6th MX12 channel is ignored and replaced           **
27
**----------------------------------------------------------------------------**
28
**                                                                            **
29
** The use of this project (hardware, software, binary files, sources and     **
30
** documentation) is only permittet for non-commercial use                    **
31
** (directly or indirectly)                                                   **
32
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"**
33
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  **
34
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE **
35
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE   **
36
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR        **
37
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF       **
38
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS   **
39
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN    **
40
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)    **
41
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE **
42
** POSSIBILITY OF SUCH DAMAGE.                                                **
43
**                                                                            **
44
------------------------------------------------------------------------------*/
45
 
46
#define ENABLE_BIT_DEFINITIONS
47
//#include <ioavr.h>
48
//#include <inavr.h>
49
#include <avr/io.h>
50
#include <avr/interrupt.h>
51
#include "main.h"
52
 
53
 
54
enum{
55
  stPPM_SYNC,
56
  stPPM_SYNC_WAIT,
57
  stPPM_CHANNEL_START,
58
  stPPM_CHANNEL_DATA,
59
  stPPM_CHANNEL_6_DATA_TRIGGER,
60
  stPPM_CHANNEL_6_DATA,
61
  stPPM_CHANNEL_7_START,
62
  stPPM_CHANNEL_7_DATA,
63
  stPPM_CHANNEL_8_START,
64
  stPPM_CHANNEL_8_DATA,
65
  stPPM_FINISH_PULSE,
66
  stPPM_FINISH_FRAME,
67
  stPPM_FRAME_END,
68
};
69
 
70
unsigned char          channel_number = 0;
71
unsigned char          ppm_state      = stPPM_SYNC;
72
unsigned char          adc_channel    = 0;
73
volatile unsigned int  channel_6      = 0xffff;                                 // set to max. for testing if conversion is valid
74
volatile unsigned int  channel_7      = 0xffff;                                 // set to max. for testing if conversion is valid
75
volatile unsigned int  channel_8      = 0xffff;                                 // set to max. for testing if conversion is valid
76
 
77
 
78
/*------------------------------------------------------------------------------
79
**                                                                            **
80
**  function :  init_pin(void)                                                **
81
**  purpose  :  Initialise I/O pins                                           **
82
**                                                                            **
83
**----------------------------------------------------------------------------*/
84
void init_pin(void)
85
{
86
 
87
  DDRA &= ~(1<<PPM_IN);                                                         // set Input Capture Pin as input
88
  PORTA |= (1<<PPM_IN);                                                         // enable pullup
89
 
90
  DDRB  |=  (1<<PPM_OUT_PIN);                                                   // configure PPM_OUT pin as output
91
  SET_PPM_OUT_LOW;                                                              // set low
92
 
93
  DDRA  &= ~(1 << CHANNEL_6_ADC);                                               // Channel 6 (pin12) input
94
  PORTA &= ~(1 << CHANNEL_6_ADC);                                               // disable pullup
95
 
96
  DDRA  &= ~(1 << CHANNEL_7_ADC);                                               // Channel 7 (pin11) input
97
  PORTA &= ~(1 << CHANNEL_7_ADC);                                               // disable pullup
98
 
99
  DDRA  &= ~(1 << CHANNEL_6_ADC);                                               // Channel 8 (pin10) input
100
  PORTA &= ~(1 << CHANNEL_6_ADC);                                               // disable pullup
101
 
102
}
103
/*-init_pin-------------------------------------------------------------------*/
104
 
105
 
106
/*------------------------------------------------------------------------------
107
**                                                                            **
108
**  function :  init_adc(void)                                                **
109
**  purpose  :  Initialise ADC registers                                      **
110
**                                                                            **
111
**----------------------------------------------------------------------------*/
112
void init_adc(void)
113
{
114
 
115
  cli();                                                                        // disable interrupts
116
 
117
  DIDR0 |= ((1<<ADC2D)|(1<<ADC1D));                                             // digital input disable for pin 11 and 12
118
  ADMUX  = 0x00;                                                                // VCC as reference voltage, select channel 0
119
  ADCSRA = (1 << ADPS2) | (1 << ADPS1)|| (0 << ADPS0);                          // 8.0 [Mhz] / 128 = 62,5 [kHz]
120
  ADCSRB = 0x00;                                                                // free running mode
121
 
122
  ADC_ENABLE;
123
 
124
  sei();                                                                        // enable interrupts
125
}
126
/*-init_adc-------------------------------------------------------------------*/
127
 
128
 
129
/*------------------------------------------------------------------------------
130
**                                                                            **
131
**  function :  init_timer1(void)                                             **
132
**  purpose  :  Initialise timer0                                             **
133
**  Note(s)  :  Frequency : 8.0 [Mhz]                                         **
134
**              8 / 8.0 Mhz : 1.00 [us]                                       **
135
**                                                                            **
136
**----------------------------------------------------------------------------*/
137
void init_timer1(void)
138
{
139
  cli();                                                                        // disable interrupts
140
 
141
  TCCR1A = ((0<<WGM11)|(0<<WGM10));                                             // CTC mode
142
  TCCR1B = ((0<<WGM13)|(1<<WGM12)|(0<<CS12)|(1<<CS11)|(0<<CS10));               // CTC mode for COMPA, prescaler 8 / 8MHz => [1.0us]
143
 
144
  CLEAR_INPUT_CAPTURE_INTERRUPT_FLAG;                                           // reset ICF flag
145
 
146
  SET_COUNTER_TO_ZERO;
147
  SET_COMPARE_COUNTER_TO_ZERO;
148
  ENABLE_INPUT_CAPTURE;
149
  DISABLE_OUTPUT_COMPARE;
150
  RISING_EDGE_TRIGGER;
151
 
152
  sei();                                                                        // enable interrupts
153
}
154
/*-init_timer1----------------------------------------------------------------*/
155
 
156
 
157
/*------------------------------------------------------------------------------
158
**                                                                            **
159
**  function :  timer1_capture_interrupt(void)                                **
160
**  purpose  :  Synchronise PPM frame and copy input events to PPM_OUT,       **
161
**              start mixing Ch6, 7 and 7 data when detect start pulse of Ch7 **
162
**                                                                            **
163
**----------------------------------------------------------------------------*/
164
//#pragma vector=TIM1_CAPT_vect
165
//static __nested __interrupt void timer1_capture_interrupt (void)
166
ISR(TIMER1_CAPT_vect)
167
{
168
   cli();                                                                       // disable interrupts
169
   unsigned int data;
170
 
171
   switch (ppm_state)
172
   {
173
      case stPPM_SYNC:                                                          // detect rising edge pulse
174
         data = ICR1;                                                           // get timer value after input capture
175
         SET_COUNTER_TO_ZERO;
176
         FALLING_EDGE_TRIGGER;
177
         if(data >= MIN_SYNC_TIME && data <= MAX_SYNC_TIME)                     // valid sync trigger
178
         {
179
            SET_PPM_OUT_HIGH;
180
            ppm_state = stPPM_CHANNEL_DATA;                                     // next state: get data
181
            channel_number = 0;
182
         }
183
         else                                                                   // trigger but not a valid sync time
184
         {
185
            SET_PPM_OUT_LOW;
186
            ppm_state = stPPM_SYNC_WAIT;                                        // next state: wait for next sync event
187
         }
188
         break;
189
 
190
      case stPPM_SYNC_WAIT:
191
         SET_PPM_OUT_LOW;                                                       // not nessecery, output should already be low
192
         SET_COUNTER_TO_ZERO;
193
         SET_CAPTURE_COUNTER_TO_ZERO;
194
         RISING_EDGE_TRIGGER;
195
         ppm_state = stPPM_SYNC;                                                // next state: try again for new sync
196
         break;
197
 
198
      case stPPM_CHANNEL_START:                                                 // detect rising edge pulse
199
         SET_COUNTER_TO_ZERO;
200
         SET_PPM_OUT_HIGH;
201
         FALLING_EDGE_TRIGGER;
202
         channel_number++;                                                      // prepare for next MX12 channel clock
203
         if(channel_number>4)                                                   // all 5 channels read
204
         {
205
            ppm_state = stPPM_CHANNEL_6_DATA_TRIGGER;                           // 7th. channel but now self created
206
            channel_number = 0;
207
         }
208
         else
209
            ppm_state = stPPM_CHANNEL_DATA;
210
         break;
211
 
212
      case stPPM_CHANNEL_DATA:                                                  // detect falling edge pulse
213
         SET_COUNTER_TO_ZERO;
214
         SET_PPM_OUT_LOW;
215
         RISING_EDGE_TRIGGER;
216
         ppm_state = stPPM_CHANNEL_START;                                       // wait for next channel rising edge pulse
217
         break;
218
 
219
      case stPPM_CHANNEL_6_DATA_TRIGGER:                                        // detect rising edge pulse
220
         SET_COUNTER_TO_ZERO;
221
         SET_PPM_OUT_LOW;
222
         SET_TIMER_TO_COMPA_CTC;
223
         DISABLE_INPUT_CAPTURE;
224
         ENABLE_OUTPUT_COMPARE;
225
         OCR1A = START_PULSE_LOW;                                               // startpulse length 0.3ms
226
         TRIGGER_INPUT_COMPARE_INTERRUPT;
227
         ppm_state = stPPM_CHANNEL_6_DATA;
228
         break;
229
 
230
      default:
231
         SET_PPM_OUT_LOW;                                                       // not nessecery, output should already be low
232
         SET_COUNTER_TO_ZERO;
233
         SET_CAPTURE_COUNTER_TO_ZERO;
234
         RISING_EDGE_TRIGGER;
235
         ppm_state = stPPM_SYNC;                                                // next state: try again for new sync
236
         break;
237
 
238
   }
239
   sei();
240
}
241
/*-timer1_capture_interrupt---------------------------------------------------*/
242
 
243
 
244
/*------------------------------------------------------------------------------
245
**                                                                            **
246
**  function :  timer1_compare_interrupt(void)                                **
247
**  purpose  :  Mixing channel 7, 8 and 9 data into ppm out,                  **
248
**              start input capture for frame synchronisation                 **
249
**                                                                            **
250
**----------------------------------------------------------------------------*/
251
//#pragma vector=TIM1_COMPA_vect
252
//__interrupt void timer1_compare_interrupt (void)
253
ISR(TIM1_COMPA_vect)
254
{
255
   cli();
256
   switch (ppm_state)
257
   {
258
      case stPPM_CHANNEL_6_DATA:                                                // create 6th channel data
259
         SET_PPM_OUT_LOW;
260
         SET_COUNTER_TO_ZERO;
261
         OCR1A = channel_6;                                                     // COMPA: 0,7ms + channel 6 ADC value
262
         ppm_state = stPPM_CHANNEL_7_START;                                     // next State
263
         break;
264
 
265
      case stPPM_CHANNEL_7_START:                                               // create 7th channel start pulse
266
         SET_PPM_OUT_HIGH;
267
         SET_COUNTER_TO_ZERO;
268
         OCR1A = START_PULSE_HIGH;                                              // startpulse length 0.3ms
269
         ppm_state = stPPM_CHANNEL_7_DATA;                                      // next State
270
         break;
271
 
272
      case stPPM_CHANNEL_7_DATA:                                                // create 7th channel data
273
         SET_PPM_OUT_LOW;
274
         SET_COUNTER_TO_ZERO;
275
         OCR1A = START_PULSE_LOW + channel_7;                                   // COMPA: 0,7ms + channel 6 ADC value
276
         ppm_state = stPPM_CHANNEL_8_START;                                     // next State
277
         break;
278
 
279
      case stPPM_CHANNEL_8_START:                                               // create 7th channel start pulse
280
         SET_PPM_OUT_HIGH;
281
         SET_COUNTER_TO_ZERO;
282
         OCR1A = START_PULSE_HIGH;                                              // startpulse length 0.3ms
283
         ppm_state = stPPM_CHANNEL_8_DATA;                                      // next State
284
         break;
285
 
286
      case stPPM_CHANNEL_8_DATA:                                                // create 7th channel data
287
         SET_PPM_OUT_LOW;
288
         SET_COUNTER_TO_ZERO;
289
         OCR1A = START_PULSE_LOW + channel_8;                                   // COMPA: 0,7ms + channel 7 ADC value
290
         ppm_state = stPPM_FINISH_PULSE;                                        // next State
291
         break;
292
 
293
    case stPPM_FINISH_PULSE:                                                    // create last pulse
294
         SET_PPM_OUT_HIGH;
295
         SET_COUNTER_TO_ZERO;
296
         OCR1A = START_PULSE_HIGH;                                              // startpulse length 0.3ms
297
         ppm_state = stPPM_FINISH_FRAME;                                        // next State
298
         break;
299
 
300
      case stPPM_FINISH_FRAME:                                                  // create extra low pulse for masking PPM_IN data of channel 7 and 8
301
         SET_PPM_OUT_LOW;
302
         SET_COUNTER_TO_ZERO;
303
         OCR1A = FORCE_LOW_END_FRAME;                                           // keep last end low; 2 channels max - 2 channels min => 2x2ms - 2x1ms + extra length = 2 ms + 1 ms = 3ms => 3000 ticks
304
         ppm_state = stPPM_FRAME_END;                                           // next State
305
         break;
306
 
307
      case stPPM_FRAME_END:
308
      default:
309
         RISING_EDGE_TRIGGER;
310
         DISABLE_OUTPUT_COMPARE;
311
         ENABLE_INPUT_CAPTURE;
312
         SET_TIMER_TO_COMPA_CTC;
313
         SET_COUNTER_TO_ZERO;
314
         SET_COMPARE_COUNTER_TO_ZERO;
315
         SET_CAPTURE_COUNTER_TO_ZERO;
316
         ppm_state = stPPM_SYNC;                                                // next State
317
         TRIGGER_INPUT_CAPTURE_INTERRUPT;
318
         break;
319
 
320
   }
321
   sei();
322
}
323
/*-timer1_compare_interrupt---------------------------------------------------*/
324
 
325
 
326
/*------------------------------------------------------------------------------
327
**                                                                            **
328
**  function :  adc_server(void)                                              **
329
**  purpose  :  Handle Analog conversion of RC channel 6, 7 and 8             **
330
**                                                                            **
331
**----------------------------------------------------------------------------*/
332
//#pragma vector=ADC_vect
333
//__interrupt void adc_server(void)
334
ISR(ADC_vect)
335
{
336
  unsigned int AdcResult;
337
 
338
  ADC_DISABLE;
339
 
340
  AdcResult = ADC;
341
  if(AdcResult > 1000)                                                          // limit conversion value
342
     AdcResult = 1000;                                                          // 1000 => 1ms
343
 
344
  ADMUX &= ~(ADC_CHANNEL_MASK);                                                 // clear channel select bits
345
 
346
  if(adc_channel == ADC_CHANNEL_6)
347
  {
348
    channel_6 = AdcResult;                                                      // set channel 6 value;
349
    adc_channel = ADC_CHANNEL_7;                                                // set next event for channel 7 conversion
350
  }
351
  else if(adc_channel == ADC_CHANNEL_7)
352
  {
353
    channel_7 = AdcResult;                                                      // set channel 7 value;
354
    adc_channel = ADC_CHANNEL_8;                                                // set next event for channel 8 conversion
355
  }
356
  else
357
  {
358
    channel_8 = AdcResult;                                                      // set channel 8 value;
359
    adc_channel = ADC_CHANNEL_6;                                                // set next event for channel 6 conversion
360
  }
361
 
362
  ADMUX  |= adc_channel;                                                        // select new conversion channel
363
 
364
  ADC_ENABLE;
365
}
366
/*-adc_server-----------------------------------------------------------------*/
367
 
368
 
369
/*------------------------------------------------------------------------------
370
**                                                                            **
371
**  function :  check_valid_adc_value(void)                                   **
372
**  purpose  :  wait until 3 ADC channels are processed at least once         **
373
**              before init Input Capture/Timer1                              **
374
**                                                                            **
375
**----------------------------------------------------------------------------*/
376
void check_valid_adc_value (void)
377
{
378
  unsigned char exit = FALSE;
379
 
380
  do
381
  {
382
     if(channel_6 < 0xffff && channel_7 < 0xffff && channel_8 < 0xffff)                               // both channels must be processed
383
        exit = TRUE;
384
 
385
  }while (!exit);
386
}
387
/*-check_valid_adc_value------------------------------------------------------*/
388
 
389
 
390
/*------------------------------------------------------------------------------
391
**                                                                            **
392
**  function :  main(void)                                                    **
393
**                                                                            **
394
**----------------------------------------------------------------------------*/
395
int main(void)
396
{
397
 
398
  init_pin();
399
  init_adc();
400
  check_valid_adc_value();                                                      // wait until both ADC channels are processed at least once
401
  init_timer1();
402
 
403
  while(1)
404
  {}
405
}
406
 
407
/*-main-----------------------------------------------------------------------*/
408