MarkT:
You are free to look at the code for millis() to work out why - its not a secret!
Please do not post "answers" ONLY for increase your posts nubers! I know arduino code is not not a secret and I have seen wiring.c code but I have not understood why I can complie without getting error but after the code execution crashes.
Thanks PaulS, the library that call millis() is in SD.ccp. SDClass::begin calls card.init that calls millis().
I have put Sd initialization on a constructor call I make before the setup(). I can solve my problem not initializing the SD in the constructor but in the setup:
myClassConstructorWithoutSdInit(0x0013a200, 0x406163FD, 4, nTentativi, ritardoProve);
void setup() {
myClass.initializeSd.
Serial.begin(9600);
Serial.println("I am in the setup");
}
void loop() {
Serial.println("loop begin");
}
but I can't understand why on the old code the complier ends well but after arduino crashes.
Thanks
#include <nodoGenerico.h>
//IMPOSTAZIONI
#define intervalloMinimoTraCampioni 2000 //180000//ritardo fra 2 campioni in millesecondi
#define sdPin 4 //per lo stalker 10, per ethernet shield 4
#define coordnatorAddressMsb 0x0013a200
#define coordnatorAddressLsb 0x406163FD
//include locali
#include "DS1307.h" //i2c clock
#include <SD.h>
#include <XBee.h>
#include <Wire.h>
#include "WProgram.h"
const int nTentativi=3;
const int ritardoProve=2000;
uint8_t timestamp[7];
nodoGenerico provaNodo(0x0013a200, 0x406163FD, nTentativi, ritardoProve);
void setup() {
Serial.begin(9600);
Serial.println("sono nel setup");
}
void loop() {
Serial.println("inizio un loop");
delay(intervalloMinimoTraCampioni);
}
the .cpp
/******************************************************************************
* Includes
******************************************************************************/
#include "nodoGenerico.h"
#include "WProgram.h" //Arduino includes
#include <SD.h>
/******************************************************************************
* Definitions
******************************************************************************/
//#define sdPin 4 //per lo stalker 10, per ethernet shield 4
/******************************************************************************
* Constructors
******************************************************************************/
nodoGenerico::nodoGenerico(uint32_t coordAddMsb, uint32_t coordAddLsb, int nTentativiParam, int ritardoProveParam)
{
Serial.begin(9600);
xbee = XBee();
addr64 = XBeeAddress64(coordAddMsb, coordAddLsb);
txStatus = ZBTxStatusResponse();
sdScritta=false;
sdPresente=false;
nTentativi=nTentativi;
ritardoProve=ritardoProve;
xbee.begin(9600);
//Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);
if (!SD.begin(sdPin)) {
Serial.println("initialization failed!");
sdPresente=false;
Serial.println("sono nel costruttore");
}
else{
Serial.println("initialization done.");
sdPresente=true;
//se la sd è presente guardo se è scritta
mioFile = SD.open("valori.txt");
if (mioFile) {
if(mioFile.available()>0 )
sdScritta=true;
mioFile.close();
}
}
}
nodoGenerico::~nodoGenerico( )
{
}
everything compiles well but at running time arduino crashes in SD.begin when reach the function millis() called by the sd library
everything compiles well but at running time arduino crashes in SD.begin
I think that this should be a clue, right there. The HardwareSerial class has a begin() method. The SD class has a begin method. The XBee class has a begin method.
Your class needs a begin() method. Constructors should not call begin() methods or execute code that belongs in a begin() method. Anything that involves pin modes, millis(), etc. is not ready for you to use until the init() method completes. The init() method is not called until after all constructors are called.
thank you for your answer. May be the program crashes also if compiling succes because of compilation order?
I found this article interesting: Constructors, C++ FAQ it is about "static" but may be the logic is similar
cantore:
thank you for your answer. May be the program crashes also if compiling succes because of compilation order?
I found this article interesting: Constructors, C++ FAQ it is about "static" but may be the logic is similar
Yes, it's a well known problem. Don't initialize stuff in static constructors is the answer. Or more accurately, don't rely upon other stuff being initialized before your stuff. It is safe to, say, move zero to a variable. It isn't safe to assume another library was initialized before yours. So, for example, you can't assume that millis() will work. You can use a begin method as PaulS suggested. Or dynamically allocate the object rather than statically allocate it.
I have not understood why I can complie without getting error but after the code execution crashes.
PaulS:
Anything that involves pin modes, millis(), etc. is not ready for you to use until the init() method completes.
I don't see the code in init() that "initializes" pin modes, except pins 0 and 1. Is that the only exception you were talking about? What if we put UCSRB = 0; in our constructor before using pinMode?
It doesn't seem like using attachInterrupt in a constructor would hurt anything either, as long as the interrupt doesn't use millis(). (Is micros() okay? I don't really understand its code)
WizenedEE:
What if we put UCSRB = 0; in our constructor before using pinMode?
That would probably be OK as it disconnects the UART.
WizenedEE:
It doesn't seem like using attachInterrupt in a constructor would hurt anything either, as long as the interrupt doesn't use millis(). (Is micros() okay? I don't really understand its code)
micros() and millis() both use the internal timer. millis() gets the last "tick" from the last interrupt, micros() takes that and adds in the "extra" from the currently-running timer to get greater resolution. Thus you need init to complete for either of those to return anything meaningful.
Of course, in your constructor, you could just assume millis() and micros() return zero. That would be reasonably close.
You are probably still better off have the constructor do nothing much, and call nodoGenerico::begin() as an initializer (in setup). Any reason not to do that? Otherwise you rely upon, in future releases, that init() doesn't do something that might clash with what you are doing.
cantore:
thank you for your answer. May be the program crashes also if compiling succes because of compilation order?
I found this article interesting: Constructors, C++ FAQ it is about "static" but may be the logic is similar
Compiling translates your language instructions into machine code. As long as there exists a proper translation from language instructions to machine code, then there will be no compilation errors.
That doesn't mean that the language instructions are doing exactly what you may think you are telling it to do, though. Most software development (like most enginering) consists of figuring out where your plans/designs/rules/code/thoughts are wrong, and fixing them, until the system behaves the way you want it to.
No static checking tool (such as a compiler) can detect that you're actually telling the system to do something other than what you intended to tell it.
If you really need to run code from a constructor, that needs to run inside init(), then you can use placement new to construct this object:
jwatte:
If you really need to run code from a constructor, that needs to run inside init(), then you can use placement new to construct this object:
...
Thank you very much for explaining how placement new is used. I was wondering how it would be helpful.