I'm writing a little PRNG class that uses the Multiply-with-carry algorithm written by George Marsaglia.
The class makes a reading of the first 4 analog pin, then it combines those readings into 2 32-bit variables used by the PRNG to generate random numbers.
But I'm having a problem with my class because it seems that if I initialize the algorithm into the class constructor, when I go to ask random numbers to my class I only get a series of 0s: the class seems not initialized. If I explicitely call the initialize() function into the setup() routine, the class does work. I would to avoid an explicit call to initialize() method beacuse I would like to do that before the user can manipulate the pins.
Yu can try this by downloading the attached library, install it into your /libraries folder, then call the example that you find in Examples/simplePRNG.
Fash the sketch as it, and then decomment the row "//initialize();" into the setup() routine and flash it again.
I can't look at the code at the moment as I am on my phone, but my guess is the class constructor gets called before the Arduino libraries initialize the pins to their default state, so anything you do in there gets undone.
I'm not certain of the sequence of events, but I think that will be being run before init() and subsequent routines. I doubt that the ADC is configured at that point.
Just including "Arduino.h" doesn't do any initialisation, it just defines all the constants and tells the compiler what functions are available. I don't know enough about the internal AVR registers to know what work the analogRead() function does in the way of configuration, so I can't be certain without cross-referencing the data sheet to the source code of analogRead().
As a rule of thumb I always provide a .begin() method in all my classes that need to do any form of setting up. That way you can guarantee that the whole system is configured and ready to roll at the point you want to start doing things.
So... I've written another constructor, doing raw readings to the ADC channels, and this code DOES work:
//class constructor
simplePRNG::simplePRNG(void) {
//initialize the internal variables
unsigned int tempInt[4] = {0, 0, 0, 0};
for (byte tempByte=0; tempByte<4; tempByte++) { //loop from MUX0 to MUX4 (ADC0..ADC3)
ADMUX |= tempByte; //choose the channel
ADMUX &= ~((1<<REFS1) | (1<<ADLAR)); //AREF set to VCC // right-adjust result
ADMUX |= (1<<REFS0); //AREF set to VCC
ADCSRA |= ((1<<ADEN) | (1<<ADPS2)); //activate ADC // prescaler set to /16
ADCSRA |= (1<<ADSC); //start convertion
while (ADCSRA & (1<<ADSC)) {} //wait for convertion to be done
tempInt[tempByte]= (ADCL | (ADCH<<8));
ADCSRA &= ~(1<<ADEN);
}
m_w = ((unsigned long)(tempInt[0]<<16));
m_w |= tempInt[1];
m_z = ((unsigned long)(tempInt[2]<<16));
m_z |= tempInt[3];
}
So the issue is into the analogRead function that, for some strange and unknown (at least to me) reasons, doesn't work inside a class constructor. Why?
If your class instance is declared at global scope then the constructor will be called before main() and in an undefined order relative to other global constructors.
main() is where the arduino library calls init() and only after that can you use the analog functions. Therefore you cannot use many of the Arduino library functions from constructors on objects declared at global scope. If this puts you off globally declared objects then your software design skills just went up a notch
If you absolutely must have a global variable then you could make it a pointer and allocate it with new in your setup() function.
In general, you should do as little as possible (typically nothing) in a constructor. Initialization should be done in setup by calling a begin method. Serial and SPI are good examples.
I'm writing a little PRNG class that uses the Multiply-with-carry algorithm written by George Marsaglia.
This is what main.cpp looks like in the Arduino core:
#include <Arduino.h>
int main(void)
{
init();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
As you can see, main() for the Arduino environment is pretty simple. It calls an init() function, maybe calls a USBDevice.attach(), followed by our setup() function, then goes into an infinite loop repeatedly calling our loop() function.
init() is responsible for initializing all the AVR hardware on the micro to a state that all the Arduino core libraries expect them to be in.
If you declare an instance of a class at the global level, it's constructor will get executed before main is executed, which means it gets executed before both init() and setup(). In particular, it's the execution prior to init(), which initizializes all the hardware, that is the source of your... situation. Any of the Arduino libraries that interact with the hardware (most of them), will not work until init() is called.
The recommended method of handling this limitation is to move that code to an init() or begin() method that you then call during setup(). That's the whole purpose of setup().