From: Pat Thoyts Date: Sun, 1 Feb 2015 22:59:01 +0000 (+0000) Subject: Added alternative tick sequence generation code. X-Git-Url: https://privyetmir.co.uk/gitweb.cgi?a=commitdiff_plain;h=84f7d9e1a5ed0778fd77abac961f54428581cb2a;p=vetinari_clock Added alternative tick sequence generation code. This version divides up 32 seconds into 128 quarter second slots and randomly places the ticks among these slots. Signed-off-by: Pat Thoyts --- diff --git a/main.c b/main.c index 0ab0b8d..46d7619 100644 --- 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 */