Best Teensy 3.1 Random Number Generator?

Status
Not open for further replies.

Jerware

Well-known member
I'm about to port a project from Arduino Uno to Teensy 3.1 that relies on unpredictable random numbers. On the Uno I use this bit of awesome code called Probably Random:

https://gist.github.com/endolith/2568571

As you can see, it uses the AVR Watchdog Interrupt for entropy, so I assume it won't compile on Teensy. Is there another method I can use on Teensy 3.1 to return "truly" random numbers? Or at least an entropy method that makes the Arduino Random() function usable? Thanks for the help!
 
read A/D that whose input pin is floating and yielding noisy numbers?
sum as unsigned all bytes in RAM?
else have to build some hardware like reversed biased diode hooked to A/D.

These are just once, to seed the standard PNG library code.
 
Some time ago I looked into porting this library, but using the LPTMR from the 1 kHz slow clock source rather than the watchdog.
 
Some time ago I looked into porting this library, but using the LPTMR from the 1 kHz slow clock source rather than the watchdog.

Cool! Mark me down as one who would use such a thing. Or any drop-in function that returns a unique byte every time the Teensy boots (with no clock).
 
You could use a random source, such as the least-significant bits of a 16-bit ADC reading, to seed an LFSR (see the wiki article here: http://en.wikipedia.org/wiki/Linear_feedback_shift_register).

LFSRs can be arranged to be maximal length, in that they don't repeat values until having output all other values. To get the seed for say a 16-bit LFSR, take 4 16-bit ADC readings, and take the 4 LSBs off each (eg. the "noise") and concatenate into a 16-bit seed. Perhaps then have the LFSR generate a random number of readings prior to outputting useful values.
 
You could use a random source, such as the least-significant bits of a 16-bit ADC reading, to seed an LFSR (see the wiki article here: http://en.wikipedia.org/wiki/Linear_feedback_shift_register).

LFSRs can be arranged to be maximal length, in that they don't repeat values until having output all other values. To get the seed for say a 16-bit LFSR, take 4 16-bit ADC readings, and take the 4 LSBs off each (eg. the "noise") and concatenate into a 16-bit seed. Perhaps then have the LFSR generate a random number of readings prior to outputting useful values.

You could also XOR with the individual Teensy's MAC address -- they are unique.

Here's some code (modified from: http://forum.pjrc.com/threads/91-teensy-3-MAC-address)

Code:
#include <stdlib.h>

// http://forum.pjrc.com/threads/91-teensy-3-MAC-address

#define LEDpin   13

void setup() {
  uint8_t m[6];
  char MAC[] = "X11:22:33:44:55:66";
    
  // Setup Serial connection
  Serial.begin(9600);   
  pinMode(LEDpin, OUTPUT); digitalWrite(LEDpin, HIGH); 
  while (!Serial) {digitalWrite(LEDpin, HIGH); delay(10); digitalWrite(LEDpin, LOW); delay(80); }

        FTFL_FCCOB0 = 0x41;             // Selects the READONCE command
        FTFL_FCCOB1 = 0x0E;             // read the given word of read once area
                                        // -- this is one half of the mac addr.
        FTFL_FSTAT = FTFL_FSTAT_CCIF;   // Launch command sequence
        while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) {}
                                    // Skip FTFL_FCCOB4 as it's always 0.
        *(m+0) = FTFL_FCCOB5;       // collect only the top three bytes,
        *(m+1) = FTFL_FCCOB6;       // in the right orientation (big endian).
        *(m+2) = FTFL_FCCOB7;       

        FTFL_FCCOB1 = 0x0F;             // read the given word of read once area
        FTFL_FSTAT = FTFL_FSTAT_CCIF;   // Launch command sequence
        while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) {}
                                    // Skip FTFL_FCCOB4 as it's always 0.
        *(m+3) = FTFL_FCCOB5;       // collect only the top three bytes,
        *(m+4) = FTFL_FCCOB6;       // in the right orientation (big endian).
        *(m+5) = FTFL_FCCOB7;       
 
for (int i=0; i < 6; i++) {Serial.write(itoa(m[i]+0x100, MAC, 16)+1); Serial.write(i < 5 ? ':' : '\n');} 
}

void loop() {} // dummy
 
Last edited:
Here's a copy of the Entropy library ported to Teensy3.

You'll need to create an empty wdt.h file in hardware/teensy/cores/teensy3/avr. Or just comment out the line #include line in Entropy.h.

Please let me know how this works for you?
 

Attachments

  • Entropy.cpp
    9.1 KB · Views: 500
I just unzipped the latest Entropy lib. Example DICE compiles for UNO and teensy ++ 2, but for teensy 3 I get compiles errors

Code:
sketchbook/libraries/Entropy/Entropy.cpp: In member function 'uint32_t EntropyClass::random()':
sketchbook/libraries/Entropy/Entropy.cpp:92:16: error: 'ATOMIC_RESTORESTATE' was not declared in this scope
sketchbook/libraries/Entropy/Entropy.cpp:92:35: error: 'ATOMIC_BLOCK' was not declared in this scope
sketchbook/libraries/Entropy/Entropy.cpp:93:3: error: expected ';' before '{' token

OK, i added #include <util/atomic.h> to Entropy.cpp. that seemed to fix it.
still worked for UNO, for DUE the include needs to be inside #ifndef ARDUINO_SAM_DUE
Paul can you let Walter Anderson know?
 
Last edited:
I checked the Teensy core, and found that Paul has provided equivalents for the Atomic functions. So I modified the header file to inlcude the util/atomic.h file if TEENSYDUINO is defined. I have uploaded the corrected Entropy.h file to the google code page as well as prepare a new zip file Entriopy-v1.0.1.zip which includes the bug fix. The correct fix (utils/atomic.h should NOT be included for the #ifndef ARDUINO_SAM_DUE is:


// Separate the ARM Due headers we use
#ifdef ARDUINO_SAM_DUE
#include <sam.h>
#include <sam3xa/include/component/component_trng.h>
#endif

// Teensy required headers
#ifdef TEENSYDUINO
#include <util/atomic.h>
#endif

// Separate AVR headers from ARM headers
#ifdef __AVR__
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/atomic.h>
#endif
 
Looks like this is fixed in version 1.0.1. I'm updating the copy on the PJRC website and in the upcoming Teensyduino 1.19...
 
Nice library implementation.
Is there any way to use this to just get an initial seed, and then turn off the ISR so that it does not interrupt any more?
I'm thinking that an end or stop method would be a nice and handy addition. The idea is I could grab an initial seed value, and then use the IRQ/watchdog for something else.
 
Nice library implementation.
Is there any way to use this to just get an initial seed, and then turn off the ISR so that it does not interrupt any more?
I'm thinking that an end or stop method would be a nice and handy addition. The idea is I could grab an initial seed value, and then use the IRQ/watchdog for something else.

On this site, Arduino random seed I have an example sketch on how to use the same basic approach on an AVR to just seed the pseudo-random number generator. If you look at the source code for the entropy library, it should be easy to modify that example for whichever teensy you want.

Now for the downside, while the example sketch uses fewer resources than the library, and the interrupt is turned off after the seed is generated, it is still attached to the interrupt vector. You'll need to find an example of how (if possible) to reassign the interrupt vector to a different handler.
 
Status
Not open for further replies.
Back
Top