Subversion Repositories Projects

Compare Revisions

Regard whitespace Rev 138 → Rev 139

/RC-Expander/branches/MX12 Expander 1.2sp/main.c
0,0 → 1,408
/*------------------------------------------------------------------------------
** **
** Ident : main.c **
** Project : MX12 2 (3) ppm channel expander **
** Author : Jacques Wanders **
** Description : main module **
** Copyright (c): 05.2008 Jacques Wanders **
** modified : 05.2008 Heinrich Fischer for use with WinAVR **
** **
**----------------------------------------------------------------------------**
** Release : v1.0 initial release **
** Date : 13-05-2008 **
**----------------------------------------------------------------------------**
** Release : v1.1 **
** Date : 13-05-2008 **
** Notes : Added Channel 9 **
**----------------------------------------------------------------------------**
** Release : v1.2 **
** Date : 22-05-2008 **
** Notes : Modified time definitions for FORCE_LOW_END_FRAME **
** and MIN_SYNC_TIME to avoid lost pulse groups **
**----------------------------------------------------------------------------**
** Release : v1.2sp **
** Date : 06-10-2008 **
** Notes : Special version, with a total of 8 channels. **
** original 6th MX12 channel is ignored and replaced **
**----------------------------------------------------------------------------**
** **
** 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. **
** **
------------------------------------------------------------------------------*/
 
#define ENABLE_BIT_DEFINITIONS
//#include <ioavr.h>
//#include <inavr.h>
#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_6_DATA_TRIGGER,
stPPM_CHANNEL_6_DATA,
stPPM_CHANNEL_7_START,
stPPM_CHANNEL_7_DATA,
stPPM_CHANNEL_8_START,
stPPM_CHANNEL_8_DATA,
stPPM_FINISH_PULSE,
stPPM_FINISH_FRAME,
stPPM_FRAME_END,
};
 
unsigned char channel_number = 0;
unsigned char ppm_state = stPPM_SYNC;
unsigned char adc_channel = 0;
volatile unsigned int channel_6 = 0xffff; // set to max. for testing if conversion is valid
volatile unsigned int channel_7 = 0xffff; // set to max. for testing if conversion is valid
volatile unsigned int channel_8 = 0xffff; // set to max. for testing if conversion is valid
 
 
/*------------------------------------------------------------------------------
** **
** function : init_pin(void) **
** purpose : Initialise I/O pins **
** **
**----------------------------------------------------------------------------*/
void init_pin(void)
{
 
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_6_ADC); // Channel 6 (pin12) input
PORTA &= ~(1 << CHANNEL_6_ADC); // disable pullup
 
DDRA &= ~(1 << CHANNEL_7_ADC); // Channel 7 (pin11) input
PORTA &= ~(1 << CHANNEL_7_ADC); // disable pullup
 
DDRA &= ~(1 << CHANNEL_6_ADC); // Channel 8 (pin10) input
PORTA &= ~(1 << CHANNEL_6_ADC); // disable pullup
 
}
/*-init_pin-------------------------------------------------------------------*/
 
 
/*------------------------------------------------------------------------------
** **
** function : init_adc(void) **
** purpose : Initialise ADC registers **
** **
**----------------------------------------------------------------------------*/
void init_adc(void)
{
 
cli(); // disable interrupts
 
DIDR0 |= ((1<<ADC2D)|(1<<ADC1D)); // digital input disable for pin 11 and 12
ADMUX = 0x00; // VCC as reference voltage, select channel 0
ADCSRA = (1 << ADPS2) | (1 << ADPS1)|| (0 << ADPS0); // 8.0 [Mhz] / 128 = 62,5 [kHz]
ADCSRB = 0x00; // free running mode
 
ADC_ENABLE;
 
sei(); // enable interrupts
}
/*-init_adc-------------------------------------------------------------------*/
 
 
/*------------------------------------------------------------------------------
** **
** function : init_timer1(void) **
** purpose : Initialise timer0 **
** Note(s) : Frequency : 8.0 [Mhz] **
** 8 / 8.0 Mhz : 1.00 [us] **
** **
**----------------------------------------------------------------------------*/
void init_timer1(void)
{
cli(); // disable interrupts
 
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
}
/*-init_timer1----------------------------------------------------------------*/
 
 
/*------------------------------------------------------------------------------
** **
** function : timer1_capture_interrupt(void) **
** purpose : Synchronise PPM frame and copy input events to PPM_OUT, **
** start mixing Ch6, 7 and 7 data when detect start pulse of Ch7 **
** **
**----------------------------------------------------------------------------*/
//#pragma vector=TIM1_CAPT_vect
//static __nested __interrupt void timer1_capture_interrupt (void)
ISR(TIMER1_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:
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 MX12 channel clock
if(channel_number>4) // all 5 channels read
{
ppm_state = stPPM_CHANNEL_6_DATA_TRIGGER; // 7th. 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;
 
case stPPM_CHANNEL_6_DATA_TRIGGER: // detect rising edge pulse
SET_COUNTER_TO_ZERO;
SET_PPM_OUT_LOW;
SET_TIMER_TO_COMPA_CTC;
DISABLE_INPUT_CAPTURE;
ENABLE_OUTPUT_COMPARE;
OCR1A = START_PULSE_LOW; // startpulse length 0.3ms
TRIGGER_INPUT_COMPARE_INTERRUPT;
ppm_state = stPPM_CHANNEL_6_DATA;
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_capture_interrupt---------------------------------------------------*/
 
 
/*------------------------------------------------------------------------------
** **
** function : timer1_compare_interrupt(void) **
** purpose : Mixing channel 7, 8 and 9 data into ppm out, **
** start input capture for frame synchronisation **
** **
**----------------------------------------------------------------------------*/
//#pragma vector=TIM1_COMPA_vect
//__interrupt void timer1_compare_interrupt (void)
ISR(TIM1_COMPA_vect)
{
cli();
switch (ppm_state)
{
case stPPM_CHANNEL_6_DATA: // create 6th channel data
SET_PPM_OUT_LOW;
SET_COUNTER_TO_ZERO;
OCR1A = channel_6; // COMPA: 0,7ms + channel 6 ADC value
ppm_state = stPPM_CHANNEL_7_START; // next State
break;
 
case stPPM_CHANNEL_7_START: // create 7th channel start pulse
SET_PPM_OUT_HIGH;
SET_COUNTER_TO_ZERO;
OCR1A = START_PULSE_HIGH; // startpulse length 0.3ms
ppm_state = stPPM_CHANNEL_7_DATA; // next State
break;
 
case stPPM_CHANNEL_7_DATA: // create 7th channel data
SET_PPM_OUT_LOW;
SET_COUNTER_TO_ZERO;
OCR1A = START_PULSE_LOW + channel_7; // COMPA: 0,7ms + channel 6 ADC value
ppm_state = stPPM_CHANNEL_8_START; // next State
break;
 
case stPPM_CHANNEL_8_START: // create 7th channel start pulse
SET_PPM_OUT_HIGH;
SET_COUNTER_TO_ZERO;
OCR1A = START_PULSE_HIGH; // startpulse length 0.3ms
ppm_state = stPPM_CHANNEL_8_DATA; // next State
break;
 
case stPPM_CHANNEL_8_DATA: // create 7th channel data
SET_PPM_OUT_LOW;
SET_COUNTER_TO_ZERO;
OCR1A = START_PULSE_LOW + channel_8; // COMPA: 0,7ms + channel 7 ADC 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_HIGH; // startpulse length 0.3ms
ppm_state = stPPM_FINISH_FRAME; // next State
break;
 
case stPPM_FINISH_FRAME: // create extra low pulse for masking PPM_IN data of channel 7 and 8
SET_PPM_OUT_LOW;
SET_COUNTER_TO_ZERO;
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
ppm_state = stPPM_FRAME_END; // next State
break;
 
case stPPM_FRAME_END:
default:
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();
}
/*-timer1_compare_interrupt---------------------------------------------------*/
 
 
/*------------------------------------------------------------------------------
** **
** function : adc_server(void) **
** purpose : Handle Analog conversion of RC channel 6, 7 and 8 **
** **
**----------------------------------------------------------------------------*/
//#pragma vector=ADC_vect
//__interrupt void adc_server(void)
ISR(ADC_vect)
{
unsigned int AdcResult;
 
ADC_DISABLE;
 
AdcResult = ADC;
if(AdcResult > 1000) // limit conversion value
AdcResult = 1000; // 1000 => 1ms
 
ADMUX &= ~(ADC_CHANNEL_MASK); // clear channel select bits
 
if(adc_channel == ADC_CHANNEL_6)
{
channel_6 = AdcResult; // set channel 6 value;
adc_channel = ADC_CHANNEL_7; // set next event for channel 7 conversion
}
else if(adc_channel == ADC_CHANNEL_7)
{
channel_7 = AdcResult; // set channel 7 value;
adc_channel = ADC_CHANNEL_8; // set next event for channel 8 conversion
}
else
{
channel_8 = AdcResult; // set channel 8 value;
adc_channel = ADC_CHANNEL_6; // set next event for channel 6 conversion
}
 
ADMUX |= adc_channel; // select new conversion channel
 
ADC_ENABLE;
}
/*-adc_server-----------------------------------------------------------------*/
 
 
/*------------------------------------------------------------------------------
** **
** function : check_valid_adc_value(void) **
** purpose : wait until 3 ADC channels are processed at least once **
** before init Input Capture/Timer1 **
** **
**----------------------------------------------------------------------------*/
void check_valid_adc_value (void)
{
unsigned char exit = FALSE;
 
do
{
if(channel_6 < 0xffff && channel_7 < 0xffff && channel_8 < 0xffff) // both channels must be processed
exit = TRUE;
 
}while (!exit);
}
/*-check_valid_adc_value------------------------------------------------------*/
 
 
/*------------------------------------------------------------------------------
** **
** function : main(void) **
** **
**----------------------------------------------------------------------------*/
int main(void)
{
 
init_pin();
init_adc();
check_valid_adc_value(); // wait until both ADC channels are processed at least once
init_timer1();
 
while(1)
{}
}
 
/*-main-----------------------------------------------------------------------*/