;*************************************************************************** ;* V - T A I L M I X E R F I R M W A R E F O R A T T I N Y 1 3 ;* ;* File Name :"VTailMixer.asm" ;* Title :V-Tail Mixer Source ;* Date :08.31.2007 ;* Version :1.0 ;* Support email :support@gadgetparadise.com ;* Target MCU :ATtiny13 ;* Source TAB size :2 ;* Compiler :AVRAssembler2 ;* ;* DESCRIPTION ;* ;* This program is V-tail mixer. It measures the standard R/C servo ;* pulses (1-2ms) on two channels with 1200 steps resolution. ;* And it generates the sum and differential pulse length ;* on two servo output channels. ;* ;* WARRANTY DISCLAIMER: ;* THIS PROGRAM IS PROVIDED AS IS WITHOUT ANY WARRANTY, EXPRESSED OR ;* IMPLIED, INCLUDING BUT NOT LIMITED TO FITNESS FOR A PARTICULAR ;* PURPOSE. THE AUTHOR ASSUME NO LIABILITY FOR DAMAGES, DIRECT OR ;* CONSEQUENTIAL, WHICH MAY RESULT FROM THE USE OF TTF2FNA SOFTWARE. ;* ;* SOFTWARE LICENSE AND DISTRIBUTION: ;* ;* The V-Tail mixer software is exclusively owned by Laszlo Arvai. ;* This software is released as a freeware. You may freely use or ;* distribute this program for any non-commercial purposes. ;* Distribution is permitted only for the whole software package ;* without any modifications and without any fee of charge. All ;* accompanying files must be included. ;* The source code is published under the GNU General Public ;* License. You can freely modify it or integrate it into your ;* projects even if your project is commercial. ;* But you can't use the hex files or the ;* source files in their original form for commercial ;* purpose, without a written permission from the ;* software author. ;* ;*************************************************************************** .include "tn13def.inc" ;***** Macros #define RAMINDEX( x ) Z + (x - SRAM_START) #define RAMINDEX_LOW( x ) Z + (x - SRAM_START) #define RAMINDEX_HIGH( x ) Z + (x - SRAM_START + 1) ;***** We don't need index registers (except Z) .undef XH .undef XL .undef YH .undef YL ;***** Constants .equ CHANNEL_RESOLUTION = 1200 ; resolution of channels .equ MIDDLE_VALUE = CHANNEL_RESOLUTION / 2 ; middle position value .equ CHANNEL_MIN_PULSE_LENGTH = 1200 ; min pulse length measured in timer increments .equ CHANNEL_PULSE_REPEAT_RATIO = 24000 ; PPM pulse repeat ratio measured in timer increments .equ GLITCH_TOLERANCE = 600 ; If the pulse length is lower or higher by this value than expected the pulse considered as glitch .equ PULSE_REPEAT_TIMEOUT = 200 ; Servo pulse repeat timeout value for pulse timeout (in 256x timer increment) .equ PULSE_OUT_DISABLED_STATUS = 0xff ; Pulse output disabled status code ; default input output values .equ DEFAULT_CHANNEL_OUT_VALUE = MIDDLE_VALUE + CHANNEL_MIN_PULSE_LENGTH - 256; .equ DEFAULT_CHANNEL_IN_VALUE = MIDDLE_VALUE; ;***** Pin definitions ; input pins .equ CH0_INPUT_PIN = PB3 .equ CH1_INPUT_PIN = PB4 ; output pins .equ CH0_OUTPUT_PIN = PB0 .equ CH1_OUTPUT_PIN = PB1 ;***** Reserved memory address .dseg ch0_out_status: .byte 1 ; Output Channel0 status register ch0_out_value: .byte 2 ; Output Channel0 value ch0_out_counter: .byte 2 ; Output Channel0 time counter ch1_out_status: .byte 1 ; Output Channel1 status register ch1_out_value: .byte 2 ; Output Channel1 value ch1_out_counter: .byte 2 ; Output Channel1 time counter ch0_in_status: .byte 1 ; Input Channel0 status ch0_time_stamp: .byte 2 ; Input Channel0 time stamp ch0_in_value: .byte 2 ; Input Channel0 pulse length ch1_in_status: .byte 1 ; Input Channel1 status ch1_time_stamp: .byte 2 ; Input Channel1 time stamp ch1_in_value: .byte 2 ; Input Channel1 pulse length ;***** Global Register Variables .def it_timer_high = R15 .def it_pulse_timeout = r10 ;***** EEPROM data .eseg ee_fail_save_settings: .db 0xff ;***** Interrupt table .cseg .org $0000 rjmp RESET_vect ; Reset handle .org INT0addr reti .org PCI0addr rjmp PCINT0_vect .org OVF0addr rjmp TIM0_OVF_vect .org ERDYaddr reti .org ACIaddr reti .org OC0Aaddr rjmp TIM0_COMPA_vect ; Timer0 CompareA handle .org OC0Baddr rjmp TIM0_COMPB_vect ; Timer0 CompareB handle .org WDTaddr reti .org ADCCaddr reti ;***** Code ;**************************************************************************** ;* ;* Main Program ;* ;* Folowing functions are implemented: ;* - system init ;* - load fail safe settings from EEPROM ;* - check for jupmer on servo outputs and check fail save settings if jumper detected ;* - calculate servo pulse length ;* ;* All other functions are implementend in irq functions ;* ;*************************************************************************** ;***** Main Program Register Variables .def m_temp = r16 ; Main program temp variable .def m_low = r17 .def m_high = r18 .def m_low2 = r8 .def m_high2 = r9 .def m_fail_safe_settings = r11 ;***** Code RESET_vect: ;** Init stack ldi m_temp,low(RAMEND) ; Load low byte address of end of RAM into register R16 out SPL,m_temp ; Initialize stack pointer to end of internal RAM ;** Init RAM address pointer (indirect memory access is used to avoid 32 length of lds and sts instruction) ldi ZL, low( SRAM_START ) ldi ZH, high( SRAM_START ) ; init SRAM movw Y, Z clr m_low ldi m_temp, SRAM_SIZE clr_sram: st Y+, m_low dec m_temp brne clr_sram ;** Load fail safe settigs from the EEPROM ldi m_temp, ee_fail_save_settings ; set address out EEARL, m_temp sbi EECR, EERE ; start read in m_fail_safe_settings, EEDR ; read data ;** Check for jumper connection between two output pins ; setup port (OUT0 - output, OUT1 - input) ldi m_temp, (1<<(CH0_OUTPUT_PIN)) out DDRB, m_temp ; activate weak pull up ldi m_temp, (1<<(CH1_OUTPUT_PIN)) out PORTB, m_temp rcall short_delay ; check if input pin is 0 sbic PINB, CH1_OUTPUT_PIN rjmp normal_start ; change output to 1 sbi PORTB, CH0_OUTPUT_PIN rcall short_delay ; check if input pin is 1 sbis PINB, CH1_OUTPUT_PIN rjmp normal_start ; change output to 0 cbi PORTB, CH0_OUTPUT_PIN rcall short_delay ; check if input pin is 0 sbic PINB, CH1_OUTPUT_PIN rjmp normal_start ; change output to 1 sbi PORTB, CH0_OUTPUT_PIN rcall short_delay ; check if input pin is 1 sbis PINB, CH1_OUTPUT_PIN rjmp normal_start ; change output to 0 cbi PORTB, CH0_OUTPUT_PIN rcall short_delay ; check if input pin is 0 sbic PINB, CH1_OUTPUT_PIN rjmp normal_start settings_change: ; invert settings com m_fail_safe_settings ; store settings in EEPROM ldi m_temp, (0< 512 ldd ch0_out_temp, RAMINDEX_HIGH(ch0_out_counter); load counter high cpi ch0_out_temp, 2 brlo oca_counter_lower dec ch0_out_temp ; decrement counter by 256 std RAMINDEX_HIGH(ch0_out_counter), ch0_out_temp rjmp oca_it_cleanup oca_counter_lower: ; divide remaing count into two equal parts ldd ch0_out_temp, RAMINDEX_LOW(ch0_out_counter) ldd ch0_out_temp2, RAMINDEX_HIGH(ch0_out_counter) lsr ch0_out_temp2 ror ch0_out_temp adc ch0_out_temp2, ch0_out_temp ; store counter std RAMINDEX_LOW(ch0_out_counter), ch0_out_temp2 clr ch0_out_temp2 std RAMINDEX_HIGH(ch0_out_counter), ch0_out_temp2 ; setup compare value in ch0_out_temp2, OCR0A add ch0_out_temp2, ch0_out_temp out OCR0A, ch0_out_temp2 rjmp oca_increment_status oca_st2: cpi ch0_out_temp, 2 brne oca_st3 ;** if status is 2 ;(preparation for falling edge) ; set last part of timing ldd ch0_out_temp, RAMINDEX(ch0_out_counter) in ch0_out_temp2, OCR0A add ch0_out_temp, ch0_out_temp2 out OCR0A, ch0_out_temp ; enable pin change cli in ch0_out_temp, TCCR0A ori ch0_out_temp, 1< 512 ldd ch1_out_temp, RAMINDEX_HIGH(ch1_out_counter) ; load counter high cpi ch1_out_temp, 2 brlo ocb_counter_lower dec ch1_out_temp ; decrement counter by 256 std RAMINDEX_HIGH(ch1_out_counter), ch1_out_temp rjmp ocb_it_cleanup ocb_counter_lower: ; divide remaing count into two equal parts ldd ch1_out_temp, RAMINDEX_LOW(ch1_out_counter) ldd ch1_out_temp2, RAMINDEX_HIGH(ch1_out_counter) lsr ch1_out_temp2 ror ch1_out_temp adc ch1_out_temp2, ch1_out_temp ; store counter std RAMINDEX_LOW(ch1_out_counter), ch1_out_temp2 clr ch1_out_temp2 std RAMINDEX_HIGH(ch1_out_counter), ch1_out_temp2 ; setup compare value in ch1_out_temp2, OCR0B add ch1_out_temp2, ch1_out_temp out OCR0B, ch1_out_temp2 rjmp ocb_increment_status ocb_st2: cpi ch1_out_temp, 2 brne ocb_st3 ;** if status is 2 ;(preparation for falling edge) ; set last part of timing ldd ch1_out_temp, RAMINDEX(ch1_out_counter) in ch1_out_temp2, OCR0B add ch1_out_temp, ch1_out_temp2 out OCR0B, ch1_out_temp ; enable pin change cli in ch1_out_temp, TCCR0A ori ch1_out_temp, 1<