Subversion Repositories Projects

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

/*------------------------------------------------------------------------------
** Ident                  : main.c                                            **
** Project                : MX16s 8->10 ppm channel expander                  **
** Author                 : lakeroe                                           **
** Description            : main module                                       **
** Copyright (c)          : 12.2011 lakeroe                                   **
** Original code and idea : Jacques Wanders                                   **
**                          http://forum.mikrokopter.de/topic-4405.html       **
**                          http://forum.mikrokopter.de/topic-4556.html       **
**----------------------------------------------------------------------------**
** Release                : v1.0 initial release                              **
** Date                   : 25-12-2011                                        **
**----------------------------------------------------------------------------**
** The use of this project (hardware, software, binary files, sources and     **
** documentation) is only permittet for non-commercial use                    **
** (directly or indirectly)                                                   **
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"**
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  **
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE **
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE   **
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR        **
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF       **
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS   **
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN    **
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)    **
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE **
** POSSIBILITY OF SUCH DAMAGE.                                                **
------------------------------------------------------------------------------*/


#include <avr/io.h>
#include <avr/interrupt.h>
#include "main.h"

enum
 {
   stPPM_SYNC,
   stPPM_SYNC_WAIT,
   stPPM_CHANNEL_START,
   stPPM_CHANNEL_DATA,
   stPPM_CHANNEL_9_DATA,
   stPPM_CHANNEL_10_START,
   stPPM_CHANNEL_10_DATA,
   stPPM_FINISH_PULSE,
   stPPM_FRAME_END
 };

unsigned char channel_number = 0;
unsigned char ppm_state      = stPPM_SYNC;

// timer1_capture_interrupt (void)
// Synchronise PPM frame and copy input events to PPM_OUT, start mixing Ch9,10 data when detect start pulse of Ch9
ISR (TIM1_CAPT_vect)
 {
   cli ();                                                                      // disable interrupts
   unsigned int data;

   switch (ppm_state)
    {
      case stPPM_SYNC:                                                          // detect rising edge pulse
        data = ICR1;                                                            // get timer value after input capture
        SET_COUNTER_TO_ZERO;
        FALLING_EDGE_TRIGGER;
        if(data >= MIN_SYNC_TIME && data <= MAX_SYNC_TIME)                      // valid sync trigger
         {
           SET_PPM_OUT_HIGH;
           ppm_state = stPPM_CHANNEL_DATA;                                      // next state: get data
           channel_number = 0;
         }
        else                                                                    // trigger but not a valid sync time
         {
           SET_PPM_OUT_LOW;
           ppm_state = stPPM_SYNC_WAIT;                                         // next state: wait for next sync event
         }
        break;

      case stPPM_SYNC_WAIT:                                                     // detect falling edge pulse
        SET_PPM_OUT_LOW;                                                        // not nessecery, output should already be low
        SET_COUNTER_TO_ZERO;
        SET_CAPTURE_COUNTER_TO_ZERO;
        RISING_EDGE_TRIGGER;
        ppm_state = stPPM_SYNC;                                                 // next state: try again for new sync
        break;

      case stPPM_CHANNEL_START:                                                 // detect rising edge pulse
        SET_COUNTER_TO_ZERO;
        SET_PPM_OUT_HIGH;
        FALLING_EDGE_TRIGGER;
        channel_number++;                                                       // prepare for next MX16s channel clock
        if(channel_number>7)                                                    // all eight channels read
         {
           SET_COUNTER_TO_ZERO;
           SET_PPM_OUT_HIGH;
           SET_TIMER_TO_COMPA_CTC;
           DISABLE_INPUT_CAPTURE;
           ENABLE_OUTPUT_COMPARE;
           OCR1A = START_PULSE;                                                 // startpulse length 0.4ms
           TRIGGER_INPUT_COMPARE_INTERRUPT;
           ppm_state = stPPM_CHANNEL_9_DATA;                                    // 9th. channel but now self created
           channel_number = 0;
         }
        else
          ppm_state = stPPM_CHANNEL_DATA;
        break;

      case stPPM_CHANNEL_DATA:                                                  // detect falling edge pulse
        SET_COUNTER_TO_ZERO;
        SET_PPM_OUT_LOW;
        RISING_EDGE_TRIGGER;
        ppm_state = stPPM_CHANNEL_START;                                        // wait for next channel rising edge pulse
        break;

      default:
        SET_PPM_OUT_LOW;                                                        // not nessecery, output should already be low
        SET_COUNTER_TO_ZERO;
        SET_CAPTURE_COUNTER_TO_ZERO;
        RISING_EDGE_TRIGGER;
        ppm_state = stPPM_SYNC;                                                 // next state: try again for new sync
        break;
    }
   sei ();
 }

// timer1_compare_interrupt (void)
// Mixing channel 9,10 data into ppm out, start input capture for frame synchronisation
ISR (TIM1_COMPA_vect)
 {
   cli ();
   switch (ppm_state)
    {
      case stPPM_CHANNEL_9_DATA:
        SET_PPM_OUT_LOW;
        SET_COUNTER_TO_ZERO;
        if (PINA & (1 << CHANNEL_9))                                            // Channel 9 on/off
          OCR1A = PPM_PULSE_MAX - START_PULSE;
        else
          OCR1A = PPM_PULSE_MIN - START_PULSE;
        // set OCR1A between [PPM_PULSE_MIN-START_PULSE] and [PPM_PULSE_MAX-START_PULSE] for transmitting analog value
        ppm_state = stPPM_CHANNEL_10_START;                                     // next State
        break;

      case stPPM_CHANNEL_10_START:
        SET_PPM_OUT_HIGH;
        SET_COUNTER_TO_ZERO;
        OCR1A = START_PULSE;                                                    // startpulse length 0.4ms
        ppm_state = stPPM_CHANNEL_10_DATA;                                      // next State
        break;

      case stPPM_CHANNEL_10_DATA:
        SET_PPM_OUT_LOW;
        SET_COUNTER_TO_ZERO;
        if (PINA & (1 << CHANNEL_10))                                           // Channel 10 on/off
          OCR1A = PPM_PULSE_MAX - START_PULSE;
        else
          OCR1A = PPM_PULSE_MIN - START_PULSE;
        // set OCR1A between [PPM_PULSE_MIN-START_PULSE] and [PPM_PULSE_MAX-START_PULSE] for transmitting analog value
        ppm_state = stPPM_FINISH_PULSE;                                         // next State
        break;

      case stPPM_FINISH_PULSE:                                                  // create last pulse
        SET_PPM_OUT_HIGH;
        SET_COUNTER_TO_ZERO;
        OCR1A = START_PULSE;                                                    // startpulse length 0.4ms
        ppm_state = stPPM_FRAME_END;                                            // next State
        break;

      case stPPM_FRAME_END:
      default:
        SET_PPM_OUT_LOW;
        RISING_EDGE_TRIGGER;
        DISABLE_OUTPUT_COMPARE;
        ENABLE_INPUT_CAPTURE;
        SET_TIMER_TO_COMPA_CTC;
        SET_COUNTER_TO_ZERO;
        SET_COMPARE_COUNTER_TO_ZERO;
        SET_CAPTURE_COUNTER_TO_ZERO;
        ppm_state = stPPM_SYNC;                                                 // next State
        TRIGGER_INPUT_CAPTURE_INTERRUPT;
        break;
    }
   sei ();
}

int main (void)
 {
   cli ();                                                                      // disable interrupts

   DDRA &= ~(1<<PPM_IN);                                                        // set Input Capture Pin as input
   PORTA |= (1<<PPM_IN);                                                        // enable pullup

   DDRB  |=  (1<<PPM_OUT_PIN);                                                  // configure PPM_OUT pin as output
   SET_PPM_OUT_LOW;                                                             // set low

   DDRA  &= ~(1 << CHANNEL_9);                                                  // Channel 9 (Pin 10) input
   PORTA |=  (1 << CHANNEL_9);                                                  // enable pullup

   DDRA  &= ~(1 << CHANNEL_10);                                                 // Channel 10 (Pin 9) input
   PORTA |=  (1 << CHANNEL_10);                                                 // enable pullup

   TCCR1A = ((0<<WGM11)|(0<<WGM10));                                            // CTC mode
   TCCR1B = ((0<<WGM13)|(1<<WGM12)|(0<<CS12)|(1<<CS11)|(0<<CS10));              // CTC mode for COMPA, prescaler 8 / 8MHz => [1.0us]

   CLEAR_INPUT_CAPTURE_INTERRUPT_FLAG;                                          // reset ICF flag
   SET_COUNTER_TO_ZERO;
   SET_COMPARE_COUNTER_TO_ZERO;
   ENABLE_INPUT_CAPTURE;
   DISABLE_OUTPUT_COMPARE;
   RISING_EDGE_TRIGGER;

   sei ();                                                                      // enable interrupts

   while(1);
 }