#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)
{
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 */
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);
}
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)
{
break;
}
}
+#endif /* !SEQUENCE_MODE */