Blame |
Last modification |
View Log
| RSS feed
/*------------------------------------------------------------------------------
** Ident : main.c **
** Project : MX16s 8->9 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_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 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 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_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
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);
}