goodwatch/firmware/rng.c
ea cf8c0946a2 Addressing #67 - RNG now has more uniform distribution
Counterintuitively, removing the code that changes deviders and speed
makes for a more uniform output.

Review and close related issue if ok.
2018-02-12 01:57:10 +01:00

62 lines
1.9 KiB
C

/*! \file rng.c
\brief Better random number generator.
*/
#include <msp430.h>
#include "rng.h"
//SLA338 inspired RNG to be used as a seed for regular PRNG
// see http://www.ti.com/lit/an/slaa338/slaa338.pdf for more details
unsigned int true_rand(void) {
int i, j;
unsigned int seed = 0;
unsigned int UCSCTL1_save = UCSCTL1;// save state and restore later
unsigned int UCSCTL4_save = UCSCTL4;
unsigned int UCSCTL5_save = UCSCTL5;
unsigned int TA0CCTL2_save = TA0CCTL2;
unsigned int TA0CTL_save = TA0CTL;
TA0CTL = 0x0; // stop timer
/* setup , according to SLA338:
Timer_A is setup in capture mode. SMCLK is set to the DCO and
set as the input clock to Timer_A. ACLK is set to the VLO,
which is the trigger for the capture.
*/
UCSCTL4 = SELA_1 | SELS_3; // ACLK to VLO, SMCLK to DCO
// According to cc430f6137.pdf TA0CCTL2 CCI2B is ACLK, therefore CCIS_1
TA0CCTL2 = CAP| CM_1 | CCIS_1;
// capture mode, on rising edge
TA0CTL = TASSEL_2 | MC_2; // Timer_A clock source is SMCLK, continuous mode
/* Generate bits */
for (i = 0; i < 16; i++) {
unsigned int ones = 0;
for (j = 0; j < 5; j++) {
while(!(TA0CCTL2 & CCIFG)); // wait till interrupt
TA0CCTL2 &= ~CCIFG; // clear interrupt
if (1 & TA0CCR2) {// sample LSb
ones++;
}
}
seed <<= 1;
if (ones >= 3) //majority of 5 samples
seed |= 1;
// even though SLA338 recomends changing dividers and speed to increase
// uniformity, tests have shown better results with these two lines disabled
//UCSCTL1 += 5; // update DCORSEL to change speed
//UCSCTL5 ^= ((seed & 3) << 8); // update ALCK divider
}
// restore everything we've been messing with
UCSCTL1 = UCSCTL1_save;
UCSCTL4 = UCSCTL4_save;
UCSCTL5 = UCSCTL5_save;
TA0CCTL2 = TA0CCTL2_save;
TA0CTL = TA0CTL_save;
return seed;
}