energia / Energia

Fork of Arduino for the Texas Instruments LaunchPad's
http://energia.nu
Other
795 stars 671 forks source link

Tiva C - hang in micros() during an object constructor execution #369

Closed wongss closed 10 years ago

wongss commented 10 years ago

We created an object that has a constructor that calls micros() and we observe that the program hang there.

This is the code for the object:

// -------------------------------------------------
// constructor
DELAYMS_T::DELAYMS_T() {
    dlySet(0); // calling a member function
}
// -------------------------------------------------
void DELAYMS_T::dlySet( uint32_t ms ) {
    startTimeus = micros(); // start from current time
    if (ms == 0) {
        desiredDlyus = 0;
        wasInit = false;
    }
    else {
        desiredDlyus = ms*1000; // in us
        wasInit=true;
    }
}

When we just create a global object below, the whole program hang. DELAYMS_T d;

When we comment out "dlySet(0);" in the constructor, the sketch works again. Thus we suspect the the library micros() causes it to hang.

The same codes has been working in Arduino.

We suspect that the energia run-time environment initialization was not complete when the micros() is called, causing it to hang.

It is rather non-ideal for us to do this workaround (i.e. do not call dlySet() in constructor) just to allow us to move on. Is there anything that can be done so that it would work in energia for launchpad just like in Arduino.

spirilis commented 10 years ago

Hi- C++ constructors occur before Energia's actual main() init routine, which causes all timing and I/O related functions to fail or hang. I have a patch submitted to correct this for better compatibility with Arduino libraries that have been written "dirty" like this -- see https://github.com/energia/Energia/pull/360

Ordinarily, you do not want to perform this type of stuff inside a C++ constructor; in no small part because you can't predict the order of execution for the various C++ constructors that need to run. It is customary to perform this init inside a "begin()" type of method within the class. See Energia and Arduino's built-in libraries for examples.

@robertinant - This might be another good example justifying the inclusion of aforementioned Issue 360's pull request. So far I only have a patch for Tiva-C though; this same issue would probably fail on the MSP430 platform.

wongss commented 10 years ago

Thank you for the follow-up.

I feel that it is very convenient (even considered valid?) to assume that Arduino like basic core system is ready before application classes constructors execution. C++ is significantly better than C and one of the reasons is its constructor. I was happily doing that in Arduino and was caught by surprise when I tried it in Tiva C.

spirilis commented 10 years ago

Well for what it's worth, I think what you are doing is generally considered bad form and/or unsupported in Arduino too. If it works in Arduino then obviously I'm wrong there about it being unsupported, but I am still fairly certain it's considered "bad form". On PC and other higher-end platforms C++ constructors are a great place to do that stuff, but on MCUs..... things are just different.

A post from the Arduino forum suggests I'm right- http://forum.arduino.cc/index.php/topic,23708.0.html Another post (not Arduino forum but talks about similar matters)- http://stackoverflow.com/questions/9683869/arduino-setup-wont-start

I guess I haven't found any real word one way or another from the Arduino developers as to what to do here, but I just recall this conversation from way back in my own Arduino days.

wongss commented 10 years ago

Accept that it is a bad form as it makes assumptions which may not be valid. Especially for a bare microcontroller environment.

I just tried a class constructor with Serial.begin() in Arduino (1.5.6-r2) as pointed out in the 1st link and created a global object. It does not work.

On the other hand, not sure if it is valid to consider Arduino (or alikes) as a simple program execution environment, comparing to a PC with a full OS environment. If yes, may be we can consider functions like micros() and millis() as basic "system calls". This is just an opinion.

Thanks for providing energia to make our programming so much easier.

rei-vilo commented 10 years ago

If I remember right, this issue has been previously discussed. The then temporary solution consisted on

I confirm the issue and hope for a solution.

spirilis commented 10 years ago

@rei-vilo See issue #360, this should actually be a solution for the Tiva to provide GPIO and timer access during constructor. It doesn't guarantee order of constructor execution, but that probably doesn't apply to this specific case. Curious if Robert or yourself have any questions... I've tested it with the TM4C123 and TM4C129 LaunchPads so far with no ill effects.

robertinant commented 10 years ago

Thanks for the patch in issue #360 @spirilis, I just pulled it in. I would love to see something similar for MSP430. I never looked at where the startup code is for msp430 so any ideas would be greatly appreciated.

spirilis commented 10 years ago

Thanks! I'll see if I can track down how mspgcc's crt0.S works, I guess I'll need to examine the source for the old msp430-libc for that. In the future RH GCC world that is provided by Newlib and I do have a tiny bit of experience with that (from my Renesas RX experiments).