Added alternative tick sequence generation code.
authorPat Thoyts <patthoyts@users.sourceforge.net>
Sun, 1 Feb 2015 22:59:01 +0000 (22:59 +0000)
committerPat Thoyts <patthoyts@users.sourceforge.net>
Sun, 1 Feb 2015 22:59:01 +0000 (22:59 +0000)
This version divides up 32 seconds into 128 quarter second slots and
randomly places the ticks among these slots.

Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>
main.c

diff --git a/main.c b/main.c
index 0ab0b8de18ae3ac56058f9e9a5d308549db6d5df..46d761987f2d69f8a1b0a93d6fadd3d5fea5867d 100644 (file)
--- a/main.c
+++ b/main.c
@@ -19,6 +19,8 @@
 #define CLKP BIT6 /* P1.6 */
 #define CLKN BIT7 /* P1.7 */
 
+#define SEQUENCE_MODE 1
+
 static uint16_t prng_state = 0xACE1u;
 static void my_srand(uint16_t seed)
 {
@@ -34,16 +36,67 @@ my_rand()
     return prng_state;
 }
 
+/* NOTE: using 16 bit integers as MSP430 has 16 bit registers */
+static uint16_t g_timing[8]; /* 128 bits each representing a quarter second */
+static int g_tick_index = 0;
+
+inline uint16_t get_tick_value(uint16_t x)
+{
+    /* x>>4 is our index to the array (top 3 bits). x & 0xF is the bit we want. */
+    return (g_timing[x>>4] >> (x & 0xF)) & 0x1;
+}
+inline void set_tick_value(uint16_t x)
+{
+    g_timing[x>>4] |= (1 << (x & 0xF));
+}
+/* reset the bit array to zeros efficiently. This loop takes less code than memset */
+inline void reset_timing()
+{
+    int n;
+    for (n = 0; n < sizeof(g_timing); ++n) 
+        g_timing[n] = 0;
+}
+
+/*
+ * create a sequence of random ticks covering 32 seconds
+ * 
+ * The array needs to have 32 random elements set high.
+ * To do this we generate 32 different random numbers to use as
+ * indexes for the bits that will be set high.
+ * If the index is already set, we just discard that number and try for a new one.
+ */
+static void
+create_timing(void)
+{
+    int count = 32;
+    reset_timing();
+    while (count)
+    {
+        /* select a random tick */
+        uint8_t tick = my_rand() & 0x7f;
+        /* if this tick has already been used, try again. */
+        if (get_tick_value(tick) != 0)
+            continue;
+
+        set_tick_value(tick);
+        --count;
+    }
+}
+
 static void
 setup(void)
 {
     P1DIR = 0xff; /* set P1.* to output for reduced power consumption */
     P1OUT = CLKP | CLKN;
     
-    /* set the counter to match on 511 which is 1s for 32kHz/8/8 (timer
-     * re-divides the interrupt clock by 8 */
-    TACCR0 = 15; /* count 16 intervals for 31ms delay */
-    /* enable the clock interrupt mode for TACCR0 match */
+    /* The crystal with the timer divider and clock dividers both at 8
+     * generates 512 ticks per second (32768/8/8)
+     * 16 of these is about 31ms
+     * 128 of the is 250ms.
+     * We want to energise the clock coil for around 30ms so this is the
+     * smallest time slice used for calling the interrupt handler.
+     */
+    TACCR0 = 15; /* call the interrupt every 16 divided clock ticks (31.25ms) */
     TACCTL0 = CCIE;
     /* set timer A to use the aux clock in UP mode with ACLK/8 divider */
     TACTL = TASSEL_1 | MC_1 | ID_3; /* and starts the timer */
@@ -61,12 +114,12 @@ main(void)
 
     my_srand(0xACE1u); /* FIX ME: get a physically derived seed */
     setup();
+    create_timing();
 
     /* enable global interrupts */
     eint();
 
     while (1) {
-        /* do nothing forever, timer interrupts drive the leds */
         /* enter low power mode 3 with interrupts enabled) */
         _BIS_SR(LPM3_bits + GIE);
     }
@@ -93,8 +146,31 @@ enum State {
     State_SkipTwo, State_BeginTriple, State_NextTriple,
 };
 enum State state = State_Wait;
-static uint8_t count = 0, offset = 0;
+static uint8_t count = 0;
 
+#if SEQUENCE_MODE
+interrupt(TIMER0_A0_VECTOR)
+TIMERA0_ISR(void)
+{
+    /* clear the interrupt flag */
+    TACCTL0 &= ~CCIFG;
+    ++count;
+    if (count == 1)
+        deenergize_coil();
+    if (count == 8) /* every 250ms */
+    {
+        count = 0;
+        if (get_tick_value(g_tick_index++))
+            energize_coil();
+        if (g_tick_index > 127)
+        {
+            g_tick_index = 0;
+            create_timing();
+        }
+    }
+}
+#else /* !SEQUENCE_MODE */
+static uint8_t offset = 0;
 interrupt(TIMER0_A0_VECTOR)
 TIMERA0_ISR(void)
 {
@@ -161,3 +237,4 @@ TIMERA0_ISR(void)
             break;
     }
 }
+#endif /* !SEQUENCE_MODE */