Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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