Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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