From b1a7e65e86e9f6fc86526ae45f38696eb4ab42ac Mon Sep 17 00:00:00 2001 From: Philipp Hachtmann Date: Thu, 23 Feb 2017 05:27:51 +0100 Subject: [PATCH] trennfix/sw: Temporary first working time measurement method Signed-off-by: Philipp Hachtmann --- trennfix/sw/config/trennfix_0.4.h | 17 +- trennfix/sw/include/pin_magic.h | 4 +- trennfix/sw/mm/include/mm/mm_switch.h | 10 +- trennfix/sw/mm/src/mm_switch.c | 262 ++++++++++++++------------ 4 files changed, 164 insertions(+), 129 deletions(-) diff --git a/trennfix/sw/config/trennfix_0.4.h b/trennfix/sw/config/trennfix_0.4.h index b0c7815..b3b6b25 100644 --- a/trennfix/sw/config/trennfix_0.4.h +++ b/trennfix/sw/config/trennfix_0.4.h @@ -25,6 +25,9 @@ static inline void setup_hw(void) OUTPUT_PIN(PIN_DRIVE); OUTPUT_PIN(PIN_LED); OUTPUT_PIN(PIN_TRIGGER); + setpin(PIN_LED, 0); + setpin(PIN_TRIGGER, 0); + setpin(PIN_BTN, 1); /* Need pullup */ GIMSK |= _BV(PCIE); /* Enable pin change interrupt for sense port */ @@ -36,8 +39,10 @@ static inline void setup_hw(void) /* Setup timer 0, used for mm_switch */ TCCR0A = 0; /* Normal mode */ TCCR0B = 2; /* Prescaler 8 */ - TIMSK |= _BV(OCIE0A); /* Get a match interrupt */ - OCR0A = 100; TCCR0B = 2; + // TIMSK |= _BV(OCIE0A); /* Get a match interrupt */ + TIMSK |= _BV(TOIE0); + OCR0A = 100; + TCCR0B = 2; #ifdef WITH_PWM /* Timer 1 as PWM */ @@ -77,18 +82,20 @@ static inline void __attribute__((unused)) trigger_off(void) * Configuration for mm receiver code. */ #define MM_SENSE (!PINVAL(PIN_SENSE)) -#define MM_TIMER_INT_VECT TIMER0_COMPA_vect +#define MM_TIMER_INT_VECT TIMER0_OVF_vect #define MM_TSTART { \ GTCCR |= _BV(TSM) | _BV(PSR0); \ TCNT0 = 0; \ - TIFR |= _BV(OCF0A); \ GTCCR &= ~_BV(TSM); \ } +#define MM_RESETFLAG TIFR |= _BV(OVF0) + #ifdef USE_REGISTER_VARS -uint8_t register drive_on asm("r8"); +uint8_t register drive_on asm("r12"); +uint8_t register slope asm("r13"); #endif #endif diff --git a/trennfix/sw/include/pin_magic.h b/trennfix/sw/include/pin_magic.h index 09838b0..3c64389 100644 --- a/trennfix/sw/include/pin_magic.h +++ b/trennfix/sw/include/pin_magic.h @@ -16,8 +16,8 @@ struct __ph_pin__ { #define PINON(pin) (*pin.addr |= _BV(pin.bitno)) #define PINOFF(pin) (*pin.addr &= ~_BV(pin.bitno)) -//#define PINVAL(pin) (*(pin.addr - 2) & _BV(pin.bitno) ? 1 : 0) -#define PINVAL(pin) (*(pin.addr - 2) & _BV(pin.bitno)) +#define PINVAL(pin) (*(pin.addr - 2) & _BV(pin.bitno) ? 1 : 0) +//#define PINVAL(pin) (*(pin.addr - 2) & _BV(pin.bitno)) #define setpin(pin, val) ((val) ? PINON(pin) : PINOFF(pin)) diff --git a/trennfix/sw/mm/include/mm/mm_switch.h b/trennfix/sw/mm/include/mm/mm_switch.h index 83d718b..35e1484 100644 --- a/trennfix/sw/mm/include/mm/mm_switch.h +++ b/trennfix/sw/mm/include/mm/mm_switch.h @@ -21,13 +21,19 @@ enum mm_recstate { uint8_t register shift_command asm("r2"); uint8_t register shift_function asm("r3"); uint8_t register shift_address asm("r4"); -uint8_t register recstate asm("r5"); +uint8_t register recstate asm("r5"); uint8_t register bitno asm("r6"); +uint8_t register sense_last asm("r8"); +uint8_t register time_h asm("r9"); +uint8_t register time_l asm("r10"); +uint8_t register bit_val asm("r11"); static void inline __attribute((unused)) mm_init(void) { bitno = 0; recstate = MM_IDLE; + time_h = 0; + bit_val = 23; } #else @@ -36,6 +42,8 @@ static void inline __attribute((unused)) mm_init(void) #endif + + /* * mm_switch_command - Callback function! * diff --git a/trennfix/sw/mm/src/mm_switch.c b/trennfix/sw/mm/src/mm_switch.c index 4bda473..34819e5 100644 --- a/trennfix/sw/mm/src/mm_switch.c +++ b/trennfix/sw/mm/src/mm_switch.c @@ -59,6 +59,10 @@ static uint8_t shift_command; static uint8_t shift_function; static uint8_t shift_address; static enum mm_recstate recstate = MM_IDLE; +static uint8_t sense_last = 23; +uint8_t time_h = 0; +uint8_t time_l = 0; +uint8_t bit_val = 23; #endif @@ -82,7 +86,7 @@ static const uint8_t nibble_table[16]={ }; #define lookup_nibble(nibble) nibble_table[nibble & 0xf] -static uint8_t lookup_decoder(uint8_t mm_byte) +static uint8_t __attribute__((unused)) lookup_decoder(uint8_t mm_byte) { uint8_t low; uint8_t high; @@ -95,7 +99,7 @@ static uint8_t lookup_decoder(uint8_t mm_byte) return 9 * high + low; } -static uint8_t lookup_command(uint8_t mm_command) +static uint8_t __attribute__((unused)) lookup_command(uint8_t mm_command) { uint8_t res; /* @@ -175,7 +179,6 @@ static uint8_t lookup_command(uint8_t mm_command) return res; } - /* We will shift from right to left. * XXXXXXXX XX XXXXXXXX * shift_address shift_function shift_command @@ -219,9 +222,13 @@ void shift(uint8_t value) static volatile uint8_t mm_rec_tolerated_timeouts; +#define MM_SLOW 0 +#define MM_FAST 1 -ISR(MM_TIMER_INT_VECT) { +static uint8_t style; +void mm_feed_bit(uint8_t bit, uint8_t seen_style) +{ static volatile uint8_t shift_command_first; static volatile uint8_t shift_function_first; static volatile uint8_t shift_address_first; @@ -233,63 +240,26 @@ ISR(MM_TIMER_INT_VECT) { static uint8_t function_last = 0xff; static uint8_t command_last = 0xff; #endif - MM_TSTART; - - switch(recstate) { - case MM_FIRST_FAST_SAMPLE: - recstate = MM_FIRST_SLOW_SAMPLE; - break; - - case MM_FIRST_SLOW_SAMPLE: - bitno = 0; - - case MM_SLOW_SAMPLE: - recstate = MM_SLOW_WAIT_FOR_CLOCK_DELAY; - break; - - case MM_SLOW_WAIT_FOR_CLOCK_DELAY: - recstate = MM_SLOW_WAIT_FOR_CLOCK; - return; - - case MM_FAST_SAMPLE: - recstate = MM_FAST_WAIT_FOR_CLOCK; - break; - - case MM_FAST_WAIT_FOR_CLOCK: /* A timeout! */ - if (mm_rec_tolerated_timeouts) - mm_rec_tolerated_timeouts--; - else - recstate = MM_IDLE; - return; - - case MM_SLOW_SAMPLE_DELAY: - recstate = MM_SLOW_SAMPLE; - return; - - case MM_SLOW_WAIT_FOR_CLOCK: - if (mm_rec_tolerated_timeouts) { - mm_rec_tolerated_timeouts--; - recstate = MM_SLOW_WAIT_FOR_CLOCK_DELAY; + + if (bitno == 0) + style = seen_style; + else + if (seen_style != style) { + bitno = 0; return; } - default: - recstate = MM_IDLE; - case MM_IDLE: - return; - } - - shift(MM_SENSE); + + shift(bit); bitno++; - if (bitno == 18) { /* Save first received word */ shift_address_first = shift_address; shift_function_first = shift_function; shift_command_first = shift_command; mm_rec_tolerated_timeouts = 18; - } if (bitno == 36) { + if ((shift_command == shift_command_first) && (shift_address == shift_address_first) && (shift_function == shift_function_first)) { @@ -299,14 +269,16 @@ ISR(MM_TIMER_INT_VECT) { if ((shift_address != address_last) || (shift_command != command_last) || shift_function != function_last) { #endif - address = lookup_decoder(shift_address); - if (recstate == MM_SLOW_WAIT_FOR_CLOCK_DELAY) { + if (style == MM_SLOW) { + address = lookup_decoder(shift_address); mm_switch_drive(address, shift_function, shift_command); - } else if (recstate == MM_FAST_WAIT_FOR_CLOCK) { + } else { + trigger(); + command = lookup_command(shift_command); mm_switch_command(address, command); - } - recstate = MM_IDLE; + } + bitno = 0; #ifdef MM_FILTER_REPEATED } address_last = shift_address; @@ -318,82 +290,132 @@ ISR(MM_TIMER_INT_VECT) { } } -//void __attribute((weak)) mm_switch_drive(uint8_t address, uint8_t function, uint8_t command); +ISR(__vector_timer_extra) { + //trigger(); +} -ISR(BADISR_vect) +/* + * The timeout interrupt vector does nothing else + * than incrementing the time_h round counter. + * + * It is written in naked assembly because we want to avoid pushing + * and popping of all upper registers. + */ +void __attribute__((naked)) MM_TIMER_INT_VECT(void) { - while(1) { - /* - setpin(PIN_LED, 1); - _delay_ms(30); - setpin(PIN_LED, 0); - _delay_ms(30); - setpin(PIN_LED, 1); - _delay_ms(30); - setpin(PIN_LED, 0); - _delay_ms(2000); - */ - } + asm("push r0 ; save r0 \n\t" + "in r0, __SREG__ \n\t" +#ifdef MM_USE_REGISTER_VARS + "inc %[th] \n\t" +#else + "push r1 \n\t" + "lds r1, time_h \n\t" + "inc r1 \n\t" + "sts time_h, r1 \n\t" + "pop r1 \n\t" +#endif + "out __SREG__, r0 \n\t" + "pop r0 \n\t" + // "rjmp __vector_timer_extra \n\t" + "reti \n\t" +#ifdef MM_USE_REGISTER_VARS + :: [th] "r" (time_h) +#endif + ); } -ISR(TIM0_OVF_vect) +/* + * Another naked interrupt trampoline + * + * Here we first save the timer value as fast as possible, then we jump (!) + * into the "official" interrupt handler with all its decorations. + */ +void __attribute__((naked)) PCINT0_vect(void) { - return; - while(1) { - setpin(PIN_LED, 1); - _delay_ms(30); - setpin(PIN_LED, 0); - _delay_ms(300); +#ifdef MM_USE_REGISTER_VARS + asm("in %[tl], %[tmr] \n\t" + "rjmp __vector_pinchange \n\t" + :: [tl] "r" (time_l), [tmr] "I" (_SFR_IO_ADDR(TCNT0)) + ); +#else + asm("push r0 \n\t" + "in r0, %[tmr] \n\t" + "sts time_l, r0 \n\t" + "pop r0 \n\t" + "rjmp __vector_pinchange \n\t" + :: [tmr] "I" (_SFR_IO_ADDR(TCNT0)) + ); +#endif +} + +/* Pin change interrupt vector, here we have a bit more time */ +ISR(__vector_pinchange){ + /* First kill off that timer */ + + MM_TSTART; /* Restart timer */ + + /* Account for not yet handled timer overflow */ + if (TIFR & _BV(TOV0)) { + time_h++; + TIFR |= _BV(TOV0); } -} + bit_val = !MM_SENSE; + + uint16_t duration = time_h << 8; + duration += time_l; + time_h = 0; + + /* + * The nominal length of a bit cycle is 208 us. + * This consists of 8 parts, each 26 us: + * 1 d d d d d d 0 + * + * That means that the 1 pulse is 7 * 26 = 182us + * and the short pulse is 1 * 26 = 26us. + * + * Reality seems to look not as that exact. I measure + * 26us for the clock pulse, but 196 for the long pulse. + * + */ + +#define D_MATCH(d, v) ((duration > (d * 2 - 2 * v)) && (duration < (d * 2 + 2 * v))) + + static uint8_t mm_positive = 1; + static uint8_t last_was_short = 0; -uint8_t register sense_last asm("r9"); + if (D_MATCH(26, 4)) { + if (last_was_short) + mm_positive = bit_val; + last_was_short = 1; + if (bit_val == mm_positive) + mm_feed_bit(0, MM_SLOW); + } else { + last_was_short = 0; + } -/* Pin change interrupt vector */ -ISR(PCINT0_vect){ - static uint8_t sense_last; - if (MM_SENSE && !sense_last) { - MM_TSTART; - switch(recstate) { - case MM_IDLE: + if (style == MM_SLOW) { + if (duration > 4000) { /* Maerklin inter package timeout 2ms */ bitno = 0; - recstate = MM_FIRST_FAST_SAMPLE; - break; - - case MM_FIRST_SLOW_SAMPLE: - recstate = MM_FAST_SAMPLE; - break; - - case MM_FAST_WAIT_FOR_CLOCK: - recstate = MM_FAST_SAMPLE; - mm_rec_tolerated_timeouts = 0; - break; - - case MM_SLOW_WAIT_FOR_CLOCK_DELAY: /* If clock comes early */ - recstate = MM_SLOW_SAMPLE_DELAY; - break; - - case MM_SLOW_WAIT_FOR_CLOCK: - recstate = MM_SLOW_SAMPLE_DELAY; - mm_rec_tolerated_timeouts = 0; - break; - - case MM_SLOW_SAMPLE_DELAY: - recstate = MM_SLOW_SAMPLE; - break; - - /* Not expected */ - case MM_FIRST_FAST_SAMPLE: - case MM_FAST_SAMPLE: - case MM_SLOW_SAMPLE: - recstate = MM_IDLE; - default: - break; + goto done; + } + } else { + if (duration > 2000) { /* Maerklin inter package timeout 1ms */ + bitno = 0; + goto done; } } - sense_last = MM_SENSE; + + if (bit_val != mm_positive) + goto done; + + if (D_MATCH(182, 25)) mm_feed_bit(1, MM_SLOW); + + if (D_MATCH(91, 17)) {mm_feed_bit(1, MM_FAST);} + if (D_MATCH(13, 4)) {mm_feed_bit(0, MM_FAST);} + + done: mm_switch_pinchange_callback(); } @@ -411,9 +433,7 @@ void __attribute__((weak))mm_switch_command(uint8_t address, uint8_t command) } + /****************************************************************************** * The end :-) */ - - - -- 2.32.0