Pages: [1] 2   Go Down
Author Topic: Call millis() before setup  (Read 1343 times)
0 Members and 1 Guest are viewing this topic.
italy
Offline Offline
Full Member
***
Karma: 3
Posts: 223
Muuuuu
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Creating a library that initializes SD card on the constructor I have understood that is not possible to call millis() in the code before the setup().
Code:

constructorCallingMillis(0x0013a200, 0x406163FD, 4, nTentativi, ritardoProve);

void setup() {   
  Serial.begin(9600);
  Serial.println("I am in the setup");
}

void loop() {
  Serial.println("loop begin");
  }

If I call it on that part of the sketch the compliers ends well but after the cede execution crashes. Could someone tell me why please? thanks
Logged

0
Offline Offline
Shannon Member
****
Karma: 206
Posts: 12113
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are free to look at the code for millis() to work out why - its not a secret!
Logged

[ I won't respond to messages, use the forum please ]

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 611
Posts: 49101
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Creating a library that initializes SD card on the constructor I have understood that is not possible to call millis() in the code before the setup().
That's not all it is not possible/advisable to do.

Where is the library code that calls millis()? Where is the call to create an instance of that class?
Logged

italy
Offline Offline
Full Member
***
Karma: 3
Posts: 223
Muuuuu
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
Code:

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
« Last Edit: October 04, 2011, 09:41:26 am by cantore » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 611
Posts: 49101
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You're really going to need to post all of your code.
Logged

italy
Offline Offline
Full Member
***
Karma: 3
Posts: 223
Muuuuu
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ok thanks
PDE
Code:
#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
Code:


/******************************************************************************
 * 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
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 611
Posts: 49101
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.
Logged

italy
Offline Offline
Full Member
***
Karma: 3
Posts: 223
Muuuuu
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thank you for your answer. May be the program crashes also if compiling succes because of compilation order?
I found this article interesting:
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14 it is about "static" but may be the logic is similar
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 611
Posts: 49101
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
May be the program crashes also if compiling succes because of compilation order?
Successful compilation != successful execution.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 481
Posts: 18742
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

thank you for your answer. May be the program crashes also if compiling succes because of compilation order?
I found this article interesting:
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14 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.

Quote
I have not understood why I can complie without getting error but after the code execution crashes.

That's no secret. For example I can compile this:

Code:
void setup ()
{
while (true) ;  // loop forever

pinMode (13, OUTPUT);
digitalWrite (13, HIGH);
}

void loop () {}

That will compile, but not turn on pin 13. They are two separate issues.
Logged


Offline Offline
Edison Member
*
Karma: 19
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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)
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 481
Posts: 18742
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What if we put UCSRB = 0; in our constructor before using pinMode?

That would probably be OK as it disconnects the UART.

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.
Logged


Global Moderator
Offline Offline
Brattain Member
*****
Karma: 481
Posts: 18742
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thank you for your answer. May be the program crashes also if compiling succes because of compilation order?
I found this article interesting:
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14 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:

Code:
char buffer[sizeof(MyClass)];
MyClass *instance;

inline void *operator new(void *ptr) { return ptr; }

void init() {
    instance = new(buffer) MyClass(constructor arguments);
}
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 481
Posts: 18742
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Pages: [1] 2   Go Up
Jump to: