ebus: Switch to a 10ms ticker
authorWerner Koch <wk@gnupg.org>
Sun, 12 Feb 2012 16:12:30 +0000 (17:12 +0100)
committerWerner Koch <wk@gnupg.org>
Sat, 11 Aug 2012 14:16:08 +0000 (16:16 +0200)
ebus/README
ebus/ebus.h
ebus/hardware.c
ebus/shutter.c
ebus/testnode.c

index 1e031ee..757dd7a 100644 (file)
@@ -21,7 +21,7 @@ Running an CSMA/CD protocol on the Elektor Bus.              -*- org -*-
   You also need to assign an different node-id to each node in the
   same collision domain by storing them in the EEPROM.  Due to
   restriction of RS485 protocol more than 32 nodes are not possible
-  with most modern drivers.  Do allow for easier switching we suggest
+  with most modern drivers.  To allow for easier switching we suggest
   to use only nodes ids in the range 1..30.  If more buses will
   eventually be attached the high bits may be used to identify the
   bus.  Such a simple scheme allows easy routing between buses by
index add1474..5c4600f 100644 (file)
@@ -95,6 +95,7 @@ void _lcd_puts_P (const char *progmem_s);
 
 
 /*-- Callbacks to be implemented by each node  --*/
+#define MILLISEC(a)  ((a)/10)
 void ticker_bottom (unsigned int clock);  /* Called by hardware.c. */
 
 
index ab8436c..d086643 100644 (file)
@@ -64,14 +64,23 @@ struct ee_data_s ee_data EEMEM = {NODETYPE_UNDEFINED, 0, {{0}}};
    explicit roll over after 7 days.  */
 static volatile uint16_t current_time;
 
-/* Milliseconds in the 10 second period.  */
+/* 10 milliseconds in the 10 second period.  */
 static volatile uint16_t current_clock;
 
 
 \f
 /* Read key S2.  Return true once at the first debounced leading edge
    of the depressed key.  For correct operation this function needs to
-   be called at fixed intervals. */
+   be called at fixed intervals.  If this is done using the 10ms
+   system tick the user is required to press the key for at least
+   100ms.  This should be sufficient to avoid faulty triggers due to
+   sparks and other noisy sources.  My tests using the usual PCB micro
+   keys showed that I was not able to push them for less then 30 ms,
+   50ms were achievable but a common value for a quick push was about
+   150ms to 200ms range.  With the old 1ms system tick we had a
+   threshold of 10ms which was too low to avoid all faulty trigger
+   sources; lightning and other noises triggered an unwanted event at
+   least 2 or 3 times a week.*/
 byte
 read_key_s2 (void)
 {
@@ -113,7 +122,7 @@ get_current_fulltime (byte *r_deci)
   hi = current_time;
   lo = current_clock;
   sei ();
-  *r_deci = lo/100;
+  *r_deci = lo/10;
   return hi;
 }
 
@@ -123,7 +132,7 @@ set_current_fulltime (uint16_t tim, byte deci)
 {
   cli ();
   current_time = tim;
-  current_clock = deci * 100;
+  current_clock = deci * 10;
   sei ();
   time_has_been_set = 1;
 }
@@ -144,14 +153,17 @@ set_debug_flags (uint8_t value)
  */
 
 
-/* 1ms ticker interrupt service routine. */
+/* 2ms ticker interrupt service routine. */
 ISR (TIMER2_COMPA_vect)
 {
-  uint16_t clockval;
+  static uint8_t two_ms_counter;
 
-  current_clock++;
+  if (++two_ms_counter != 5)
+    return;
+  two_ms_counter = 0;
 
-  if (current_clock >= 10000)
+  current_clock++;
+  if (current_clock >= 1000)
     {
       /* 10 seconds passed.  Bump the current time.  */
       current_time++;
@@ -160,8 +172,7 @@ ISR (TIMER2_COMPA_vect)
       current_clock = 0;
     }
 
-  clockval = current_clock;
-  ticker_bottom (clockval);
+  ticker_bottom (current_clock);
 }
 
 
@@ -199,12 +210,26 @@ hardware_setup (byte nodetype)
   UBRR0H = (UBRR_VAL >> 8) & 0x0f;
   UBRR0L = (UBRR_VAL & 0xff);
 
-  /* Timer 2: 1ms ticker.  */
+  /* Timer 2: 10ms ticker.
+
+     F_ocr = F_cpu / (PRE * (OCR+1))
+     |    F_cpu |  PRE | OCR |        F_ocr |
+     |----------+------+-----+--------------|
+     | 16000000 |   64 |  24 | 10000.000000 |
+     | 16000000 |   64 | 249 |  1000.000000 |
+     | 16000000 |  128 | 249 |   500.000000 |
+     | 16000000 | 1024 | 155 |   100.160260 |
+     #+TBLFM: $4=$1 / ($2 ($3 + 1));%f
+
+     The table indicates that there is no way to get an exact 10ms
+     timer.  It is possible to have an exact 1ms and 2ms timer.  We
+     use a 2ms timer internally along with a counter to turn it into
+     the 10ms timer.
+  */
   TCCR2A = 0x02;   /* Select CTC mode.  */
-  TCCR2B = 0x04;   /* Set prescaler to 64.  */
+  TCCR2B = 0x05;   /* Set prescaler to 128.  */
   TCNT2 = 0x00;    /* Clear timer/counter register.  */
-  OCR2A  = 249;    /* Compare value for 1ms.  Note: This is one less
-                      than the naively computed value 250.  */
+  OCR2A  = 249;    /* Compare value for 2ms.  */
   TIMSK2 = 0x02;   /* Set OCIE2A.  */
 
   /* Copy some configuration data into the RAM.  */
index 199d0ae..f781a07 100644 (file)
@@ -162,12 +162,13 @@ static void init_eeprom (byte force);
 
 
 \f
-/* This code is called by the 1ms ticker interrupt service routine
-   with the current clock value given in milliseconds from 0..9999. */
+/* This code is called by the 10ms ticker interrupt service routine
+   with the current clock value given in 10 millisecond increments
+   from 0..999. */
 void
 ticker_bottom (unsigned int clock)
 {
-  if (!(clock % 1000))
+  if (!(clock % 100))
     {
       one_second_event = 1;
       wakeup_main = 1;
@@ -256,8 +257,8 @@ trigger_action (enum action_values action)
   last_action = action;
 
   /* Now force a new transaction using the ticker interrupt.  We set
-     the delay to 1 ms so that the motor_action_event will be
-     triggered within the next millisecond.  There is no need to
+     the delay to 10 ms so that the motor_action_event will be
+     triggered within the next 10 milliseconds.  There is no need to
      disable interrupts; the worst what could happen is a double
      triggered action and that action is anyway a motor off.  Using
      this indirect method avoids a race between motor_action_delay and
@@ -284,12 +285,12 @@ motor_action (void)
 
         case motor_state_pre_off:
           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
-          newdelay = 200; /*ms*/
+          newdelay = MILLISEC (200);
           motor_state = motor_state_pre_off2;
           break;
         case motor_state_pre_off2:
           MOTOR_down &= ~_BV(MOTOR_down_BIT);/* Switch direction relay off. */
-          newdelay = 200; /*ms*/
+          newdelay = MILLISEC (200);
           motor_state = motor_state_pre_off3;
           break;
         case motor_state_pre_off3:
@@ -301,12 +302,12 @@ motor_action (void)
 
         case motor_state_pre_up:
           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
-          newdelay = 200; /*ms*/
+          newdelay = MILLISEC (200);
           motor_state = motor_state_pre_up2;
           break;
         case motor_state_pre_up2:
           MOTOR_down &= ~_BV(MOTOR_down_BIT);/* Switch direction relay off. */
-          newdelay = 200; /*ms*/
+          newdelay = MILLISEC (200);
           motor_state = motor_state_up;
           break;
         case motor_state_up:
@@ -314,7 +315,7 @@ motor_action (void)
           shutter_state = 0b11000000;
           /*                |!------- Direction set to up
            *                +-------- Motor running.        */
-          newdelay = 25000; /*ms*/
+          newdelay = MILLISEC (25000);
           motor_state = motor_state_up_ready;
           break;
         case motor_state_up_ready:
@@ -326,12 +327,12 @@ motor_action (void)
 
         case motor_state_pre_down:
           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
-          newdelay = 200; /*ms*/
+          newdelay = MILLISEC (200);
           motor_state = motor_state_pre_down2;
           break;
         case motor_state_pre_down2:
           MOTOR_down |= _BV(MOTOR_down_BIT); /* Switch direction relay on. */
-          newdelay = 200; /*ms*/
+          newdelay = MILLISEC (200);
           motor_state = motor_state_down;
           break;
         case motor_state_down:
@@ -339,7 +340,7 @@ motor_action (void)
           shutter_state = 0b10000000;
           /*                |!------- Direction set to down
            *                +-------- Motor running.        */
-          newdelay = 25000; /*ms*/
+          newdelay = MILLISEC (25000);
           motor_state = motor_state_down_ready;
           break;
         case motor_state_down_ready:
@@ -584,7 +585,7 @@ process_sensor_cmd (byte *msg)
           onewire_write_byte (0x44); /* Convert T.  */
           /* Now we need to wait at least 750ms to read the value from
              the scratchpad.  */
-          sensor_action_delay = 900; /* ms */
+          sensor_action_delay = MILLISEC (900);
           sensor_action_event = 0;
       }
       break;
@@ -660,7 +661,7 @@ send_sensor_result (void)
       onewire_write_byte (0xcc); /* Skip ROM.  */
       onewire_write_byte (0x44); /* Convert T. */
       /* Try again ...  */
-      sensor_action_delay = 1100; /*ms*/
+      sensor_action_delay = MILLISEC (1100);
       sensor_action_event = 0;
     }
 }
index cee7b7e..0b23eec 100644 (file)
@@ -172,27 +172,30 @@ main (void)
   sei (); /* Enable interrupts.  */
 
 
-    /* { */
-    /*   byte i, crc, buf[9]; */
-
-    /*   send_dbgmsg_fmt ("serial..."); */
-    /*   onewire_enable (); */
-    /*   onewire_write_byte (0x33); /\* Read ROM.  *\/ */
-    /*   for (i=0; i < 8; i++) */
-    /*     buf[i] = onewire_read_byte (); */
-    /*   _delay_ms (1); */
-    /*   crc = 0; */
-    /*   for (i=0; i < 7; i++) */
-    /*     crc = _crc_ibutton_update (crc, buf[i]); */
-
-    /*   send_dbgmsg_fmt ("%02x %02x%02x%02x %02x", */
-    /*                    buf[0], buf[1], buf[2], buf[3], buf[7]); */
-    /*   send_dbgmsg_fmt ("%02x%02x%02x %s", */
-    /*                    buf[4], buf[5], buf[6], */
-    /*                    buf[7] == crc? "ok":"bad"); */
-
-    /*   _delay_ms (2000); */
-    /* } */
+  /* for (;;) */
+  /*   { */
+  /*     byte i, crc, buf[9]; */
+
+  /*     send_dbgmsg_fmt ("serial..."); */
+  /*     onewire_enable (); */
+  /*     onewire_write_byte (0x33); /\* Read ROM.  *\/ */
+  /*     _delay_ms (50); */
+  /*     onewire_enable (); */
+  /*     for (i=0; i < 8; i++) */
+  /*       buf[i] = onewire_read_byte (); */
+  /*     _delay_ms (1); */
+  /*     crc = 0; */
+  /*     for (i=0; i < 7; i++) */
+  /*       crc = _crc_ibutton_update (crc, buf[i]); */
+
+  /*     send_dbgmsg_fmt ("%02x %02x%02x%02x %02x", */
+  /*                      buf[0], buf[1], buf[2], buf[3], buf[7]); */
+  /*     send_dbgmsg_fmt ("%02x%02x%02x %s", */
+  /*                      buf[4], buf[5], buf[6], */
+  /*                      buf[7] == crc? "ok":"bad"); */
+
+  /*     _delay_ms (2000); */
+  /*   } */
 
   for (;;)
     {
@@ -201,8 +204,8 @@ main (void)
       onewire_enable ();
       onewire_write_byte (0xcc); /* Skip ROM.  */
       onewire_write_byte (0x44); /* Convert T.  */
-      onewire_wait_for_one ();
-      _delay_ms (100);
+      /* onewire_wait_for_one (); */
+      _delay_ms (900);
       onewire_enable ();         /* Reset */
       onewire_write_byte (0xcc); /* Skip ROM.  */
       onewire_write_byte (0xbe); /* Read scratchpad.  */
@@ -222,8 +225,11 @@ main (void)
 
           send_dbgmsg_fmt ("t=%d (%d)", t, tread);
         }
+      else
+        send_dbgmsg_fmt ("badcrc");
 
-      _delay_ms (5000);
+      onewire_disable ();
+      _delay_ms (1000);
     }