trennfix/sw: Temporary first working time measurement method
authorPhilipp Hachtmann <hachti@hachti.de>
Thu, 23 Feb 2017 04:27:51 +0000 (05:27 +0100)
committerPhilipp Hachtmann <hachti@hachti.de>
Tue, 18 Apr 2023 20:03:20 +0000 (22:03 +0200)
Signed-off-by: Philipp Hachtmann <hachti@hachti.de>
trennfix/sw/config/trennfix_0.4.h
trennfix/sw/include/pin_magic.h
trennfix/sw/mm/include/mm/mm_switch.h
trennfix/sw/mm/src/mm_switch.c

index b0c78157b65925bd4a105e93a68f50cf2be3223c..b3b6b254f6f495bfd4b4bb7975fd9dc7de309aa0 100644 (file)
@@ -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
index 09838b01bd1b0b67e0c0df429809a2aa27c979f6..3c6438909e6c11713bddd9930d0bb460ca5336c0 100644 (file)
@@ -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))
 
index 83d718bb31db2590df33b5b0e4bfee2a624e5cde..35e14844250997029c2d5f4eb0c258c375e2b45d 100644 (file)
@@ -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!
  *
index 4bda4730a30e4d57c1a7f9e4e369edb5b7a86917..34819e5d626071098f1d6ca1660163799f15eb0d 100644 (file)
@@ -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 :-)
  */
-
-
-