Mike's answer uses a Fibonacci Linear Feedback Shift Register configuration, but the compactness Galois Linear Feedback Shift Register Configuration could be faster:
#define speakerPin 8
unsigned long lastClick;
void setup() {
// put your setup code here, to run once:
pinMode(speakerPin,OUTPUT);
lastClick = micros();
}
/* initialize with any 32 bit non-zero unsigned long value. */
#define LFSR_INIT 0xfeedfaceUL
/* Choose bits 32, 30, 26, 24 from http://arduino.stackexchange.com/a/6725/6628
* or 32, 22, 2, 1 from
* http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
* or bits 32, 16, 3,2 or 0x80010006UL per http://users.ece.cmu.edu/~koopman/lfsr/index.html
* and http://users.ece.cmu.edu/~koopman/lfsr/32.dat.gz
* or generate a one with https://github.com/hayguen/mlpolygen
*/
#define LFSR_MASK ((unsigned long)( 1UL<<31 | 1UL <<15 | 1UL <<2 | 1UL <<1 ))
unsigned int generateNoise(){
// See https://en.wikipedia.org/wiki/Linear_feedback_shift_register#Galois_LFSRs
static unsigned long int lfsr = LFSR_INIT; /* 32 bit init, nonzero */
/* If the output bit is 1, apply toggle mask.
* The value has 1 at bits corresponding
* to taps, 0 elsewhere. */
if(lfsr & 1) { lfsr = (lfsr >>1) ^ LFSR_MASK ; return(1);}
else { lfsr >>= 1; return(0);}
}
void loop() {
/* ... */
if ((micros() - lastClick) > 50 ) { // Changing this value changes the frequency.
lastClick = micros();
digitalWrite (speakerPin, generateNoise());
}
}
For a 16 bit implementation (faster, but only a cycle of 2^16) try:
#define LFSR_MASK 0x8016
static uint16_t lfsr = LFSR_INIT; /* 16 bit init, nonzero */
Written in a more compact form:
#define speakerPin 8
#define LFSR_INIT 0xfeed /* non-zero seed value for generateNoise() */
#define LFSR_MASK 0x8016 /* magic number from http://users.ece.cmu.edu/~koopman/lfsr/ */
unsigned long lastClick;
void setup() {
// put your setup code here, to run once:
pinMode(speakerPin,OUTPUT);
lastClick = micros();
}
unsigned int generateNoise(){
// Return 1 bit of noise using a Galois Linear Feedback Shift Register
// See https://en.wikipedia.org/wiki/Linear_feedback_shift_register#Galois_LFSRs
static uint16_t lfsr = LFSR_INIT;
if(lfsr & 1) { lfsr = (lfsr >>1) ^ LFSR_MASK ; return(1);}
else { lfsr >>= 1; return(0);}
}
void loop() {
/* ... */
if ((micros() - lastClick) > 50 ) { // Changing this value changes the frequency.
lastClick = micros();
digitalWrite (speakerPin, generateNoise());
}
}
For an 8 bit implementation (faster than 32 bit, slightly slower than 16, but only a cycle of 2^8) try:
#define LFSR_MASK 0x8e
static byte lfsr = LFSR_INIT; /* 8 bit init, nonzero */
Where the mask constants are from the 8.txt and 16.txt files at http://users.ece.cmu.edu/~koopman/lfsr/index.html
The https://github.com/hayguen/mlpolygen program can search for maximum length feedback polynomials of various bit sizes.