-
Random LED Dots: Entropy Library for Moah Speed with Less Gimcrackery
A discussion over the Squidwrench Operating Table about injecting entropy into VMs before / during their boot sequence reminded me that I wanted to try the Entropy library with my 8×8 RGB LED matrix:

8×8 RGB LED Matrix – board overview The original version trundled along with random numbers produced by timing Geiger counter ticks. The second version, digitizing the amplified noise from a reverse-biased PN junction, ran much faster.
What’s new & different: the Entropy library measures the jitter between the ATmega328 watchdog timer’s RC oscillator and the ceramic resonator (on Pro Mini boards) driving the CPU. It cranks out four bytes of uncorrelated bits every half-second, which isn’t quite fast enough for a sparkly display, but re-seeding the Arduino PRNG whenever enough entropy arrives works well enough.
One could, of course, re-seed the PRNG with Geiger bits or junction noise to the same effect. The key advantage of the Entropy library: no external hardware required. The downside: no external hardware required, so, minus those techie transistors / resistors / op amps, it will look like Just Another Arduino Project.

Reverse-bias noise amplifier – detail Le sigh.
In any event, the Entropy library has excellent documentation and works perfectly.
The Arduino PRNG can produce results fast enough for wonderfully twinkly output that’s visually indistinguishable from the “true” random numbers from the Geiger counter or PN junction. I dialed it back to one update every 5 ms, because letting it free-run turned the display into an unattractive blur.
The top trace shows the update actually happens every 6 ms:

Entropy TRNG – LED update vs refresh The lower trace shows that each matrix row refresh takes about a millisecond. Refreshes occur on every main loop iteration and interfere with the update, not that that makes any difference. Should it matter, subtract one from the update period and it’ll be all good.
The Arduino source code as a GitHub Gist:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters// Random LED Dots // Based on Entropy library using watchdog timer jitter // https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library // Ed Nisley – KE4ANU – August 2016 #include <Entropy.h> //———- // Pin assignments const byte PIN_HEARTBEAT = 8; // DO – heartbeat LED const byte PIN_SYNC = A3; // DO – scope sync const byte PIN_LATCH = 4; // DO – shift register latch clock const byte PIN_DIMMING = 9; // AO – LED dimming control // These are *hardware* SPI pins const byte PIN_MOSI = 11; // DO – data to shift reg const byte PIN_MISO = 12; // DI – data from shift reg (unused) const byte PIN_SCK = 13; // DO – shift clock to shift reg (also Arduino LED) const byte PIN_SS = 10; // DO – -slave select (must be positive for SPI output) //———- // Constants #define UPDATE_MS 5 //———- // Globals // LED selects are high-active bits and low-active signals: flipped in UpdateLEDs() // *exactly* one row select must be active in each element typedef struct { const byte Row; byte ColR; byte ColG; byte ColB; } LED_BYTES; // altering the number of rows & columns will require substantial code changes… #define NUMROWS 8 #define NUMCOLS 8 LED_BYTES LEDs[NUMROWS] = { {0x80,0,0,0}, {0x40,0,0,0}, {0x20,0,0,0}, {0x10,0,0,0}, {0x08,0,0,0}, {0x04,0,0,0}, {0x02,0,0,0}, {0x01,0,0,0}, }; byte RowIndex; #define LEDS_ON 0 #define LEDS_OFF 255 unsigned long MillisNow; unsigned long MillisThen; //– Helper routine for printf() int s_putc(char c, FILE *t) { Serial.write(c); } //– Useful stuff // Free RAM space monitor // From http://playground.arduino.cc/Code/AvailableMemory uint8_t * heapptr, * stackptr; void check_mem() { stackptr = (uint8_t *)malloc(4); // use stackptr temporarily heapptr = stackptr; // save value of heap pointer free(stackptr); // free up the memory again (sets stackptr to 0) stackptr = (uint8_t *)(SP); // save value of stack pointer } void TogglePin(char bitpin) { digitalWrite(bitpin,!digitalRead(bitpin)); // toggle the bit based on previous output } void PulsePin(char bitpin) { TogglePin(bitpin); TogglePin(bitpin); } //——— //– SPI utilities void EnableSPI(void) { digitalWrite(PIN_SS,HIGH); // make sure this is high! SPCR |= 1 << SPE; } void DisableSPI(void) { SPCR &= ~(1 << SPE); } void WaitSPIF(void) { while (! (SPSR & (1 << SPIF))) { // TogglePin(PIN_HEARTBEAT); continue; } } byte SendRecSPI(byte Dbyte) { // send one byte, get another in exchange SPDR = Dbyte; WaitSPIF(); return SPDR; // SPIF will be cleared } void UpdateLEDs(byte i) { SendRecSPI(~LEDs[i].ColB); // low-active outputs SendRecSPI(~LEDs[i].ColG); SendRecSPI(~LEDs[i].ColR); SendRecSPI(~LEDs[i].Row); analogWrite(PIN_DIMMING,LEDS_OFF); // turn off LED to quench current PulsePin(PIN_LATCH); // make new shift reg contents visible analogWrite(PIN_DIMMING,LEDS_ON); } //————— // Set LED from integer // On average, this leaves the LED unchanged for 1/8 of the calls… void SetLED(unsigned long Value) { byte Row = Value & 0x07; byte Col = (Value >> 3) & 0x07; byte Color = (Value >> 6) & 0x07; byte BitMask = (0x80 >> Col); // printf("%u %u %u %u\r\n",Row,Col,Color,BitMask); LEDs[Row].ColR &= ~BitMask; LEDs[Row].ColR |= (Color & 0x04) ? BitMask : 0; LEDs[Row].ColG &= ~BitMask; LEDs[Row].ColG |= (Color & 0x02) ? BitMask : 0; LEDs[Row].ColB &= ~BitMask; LEDs[Row].ColB |= (Color & 0x01) ? BitMask : 0; } //—————— // Set things up void setup() { pinMode(PIN_HEARTBEAT,OUTPUT); digitalWrite(PIN_HEARTBEAT,HIGH); // show we arrived pinMode(PIN_SYNC,OUTPUT); digitalWrite(PIN_SYNC,LOW); pinMode(PIN_MOSI,OUTPUT); // SPI-as-output is not strictly necessary digitalWrite(PIN_MOSI,LOW); pinMode(PIN_SCK,OUTPUT); digitalWrite(PIN_SCK,LOW); pinMode(PIN_SS,OUTPUT); digitalWrite(PIN_SS,HIGH); // OUTPUT + HIGH is required to make SPI output work pinMode(PIN_LATCH,OUTPUT); digitalWrite(PIN_LATCH,LOW); Serial.begin(57600); fdevopen(&s_putc,0); // set up serial output for printf() printf("Random LED Dots – Watchdog Entropy\r\nEd Nisley – KE4ZNU – August 2016\r\n"); Entropy.initialize(); // start up entropy collector //– Set up SPI hardware SPCR = B01110001; // Auto SPI: no int, enable, LSB first, master, + edge, leading, f/16 SPSR = B00000000; // not double data rate EnableSPI(); // turn on the SPI hardware SendRecSPI(0); // set valid data in shift registers: select Row 0, all LEDs off //– Dimming pin must use fast PWM to avoid beat flicker with LED refresh rate // Timer 1: PWM 9 PWM 10 analogWrite(PIN_DIMMING,LEDS_OFF); // disable column drive (hardware pulled it low before startup) TCCR1A = B10000001; // Mode 5 = fast 8-bit PWM with TOP=FF TCCR1B = B00001001; // … WGM, 1:1 clock scale -> 64 kHz //– lamp test: send a white flash through all LEDs printf("Lamp test begins: white flash each LED…"); digitalWrite(PIN_HEARTBEAT,LOW); // turn off while panel blinks analogWrite(PIN_DIMMING,LEDS_ON); // enable column drive for (byte i=0; i<NUMROWS; i++) { for (byte j=0; j<NUMCOLS; j++) { LEDs[i].ColR = LEDs[i].ColG = LEDs[i].ColB = 0x80 >> j; for (byte k=0; k<NUMROWS; k++) { UpdateLEDs(k); delay(25); } LEDs[i].ColR = LEDs[i].ColG = LEDs[i].ColB = 0; } } UpdateLEDs(NUMROWS-1); // clear the last LED printf(" done!\r\n"); //– Preload LEDs with random values digitalWrite(PIN_HEARTBEAT,LOW); uint32_t rn = Entropy.random(); printf("Preloading LED array with seed: %08lx\r\n",rn); randomSeed(rn); for (byte Row=0; Row<NUMROWS; Row++) { for (byte Col=0; Col<NUMCOLS; Col++) { // Col runs backwards, but we don't care LEDs[Row].ColR |= random(2) << Col; // random(2) returns 0 or 1 LEDs[Row].ColG |= random(2) << Col; LEDs[Row].ColB |= random(2) << Col; } UpdateLEDs(Row); } check_mem(); printf("SP: %u HP: %u Free RAM: %u\r\n",stackptr,heapptr,stackptr – heapptr); printf("Running…\r\n"); MillisThen = millis(); } //—————— // Run the test loop void loop() { unsigned long Hash; uint32_t rn; MillisNow = millis(); // Re-seed the generator whenever we get enough entropy if (Entropy.available()) { digitalWrite(PIN_HEARTBEAT,HIGH); rn = Entropy.random(); // printf("Random: %08lx ",rn); randomSeed(rn); digitalWrite(PIN_HEARTBEAT,LOW); } // If it's time for a change, whack a random LED if ((MillisNow – MillisThen) > UPDATE_MS) { MillisThen = MillisNow; SetLED(random()); } // Refresh LED array to maintain the illusion of constant light UpdateLEDs(RowIndex++); if (RowIndex >= NUMROWS) { RowIndex = 0; PulsePin(PIN_SYNC); } }