Shop OBEX P1 Docs P2 Docs Learn Events
difftime returns zero — Parallax Forums

difftime returns zero

doug.taylordoug.taylor Posts: 31
edited 2014-08-05 11:43 in Propeller 1
I'm trying to develop a standard loop of a fixed frequency. When I execute the following code, the elapsedSeconds variable always returns zero(0). Can anyone tell me what I am doing wrong or possibly a better way to do this?
    /**
     * This is the main TestLoopDuration program file.
     */
    
    #include "simpletools.h"                      // Include simple tools
    #include "stdbool.h"
    
    // Constants
    static volatile const int _HZ_ = 10;
    
    static volatile int _taskDuration = 0;
    
    // Function prototypes
    void MainLoop();

    int main(void)
    {
      time_t startTime;
      time_t endTime;
      double loopTime = 0.02;
      double elapsedSeconds = 0.0;
      int sleepMilliseconds = 0;
    
      while(1)
      {
        //  get a timestamp at the beginning of this loop
        startTime = time(NULL);
    
        MainLoop();
    
        // get the elapsed time in ticks
        endTime = time(NULL);
        elapsedSeconds = difftime(endTime, startTime);
        printf("  elapsed %.f\n", elapsedSeconds);
        // get the time to sleep
        sleepMilliseconds = (int)((loopTime - elapsedSeconds) * 1000);
        if (sleepMilliseconds > 0)
        {
          pause(sleepMilliseconds);
        }
      }
    }
    
    void MainLoop()
    {
      // do some time taking tasks
    
      pause(5);
    }

Comments

  • jazzedjazzed Posts: 11,803
    edited 2014-07-27 14:40
  • jazzedjazzed Posts: 11,803
    edited 2014-07-27 17:15
    The basic problem is the misunderstanding of the pause() function. Also time(NULL) returns number of seconds as documented in the cplusplus.com reference pages and many other places.

    I suggest looking at the Learn/Simple Library documentation for pause() and other simpletools.h functions. The documentation is also available in Menu -> Help -> Simple Library Reference and online at https://propsideworkspace.googlecode.com/hg/Learn/Simple Libraries Index.html. The latest IDE version 0-9-64 or higher allows mouseover F1 help.
  • doug.taylordoug.taylor Posts: 31
    edited 2014-07-28 05:09
    jazzed,

    Thank you for your response. In your first post you suggest that I look at the example at:

    http://www.cplusplus.com/reference/ctime/time/

    This is exactly what I based my code upon. I don't see a difference.

    In your next post you referred to pause() and time(NULL). I used time(NULL) exactly as it shows in the previous example. This same page states that the return value is "The current calendar time as a time_t object.". time_t is platform dependent and not necessarily a known type. When I call time() twice I should have a time_t object for the start of the loop and a time_t object for the end of the loop.

    I then use difftime() as documented here:

    http://www.cplusplus.com/reference/ctime/difftime/

    On this page it says that difftime takes two time_t values and calculates the difference. The return value is a double containing the number of seconds between the two time_t values.

    Now this is where I might have gone wrong: I made a big assumption here that seemed obvious to me. Since the unit of measure returned by difftime is seconds AND difftime returns a double THEN the return value must be able to return fractional seconds such as 0.001 as one millisecond. OTHERWISE, why return a double just to hold whole number values?

    If time_t only holds whole seconds, then I hope you can see my confusion. Please confirm my misunderstanding because the documentation says "The value returned generally represents the number of seconds since 00:00 hours, Jan 1, 1970 UTC " but it doesn't specifically say "whole seconds".

    Now, on to the pause() function. You say that I have a misunderstanding of this function. My understanding comes from the definition here:

    https://propsideworkspace.googlecode.com/hg/Learn/Simple%20Libraries/Utility/libsimpletools/html/simpletools_8h.html#a381e2d58c3d6a1f0fd8129bcc4726804

    This states: "Delay cog from moving on to the next statement for a certain length of time." This is what I want it to do. Also, "The default time increment is 1 ms, so pause(100) would delay for 100 ms = 1/10th of a second" which is also exactly what I was trying to do. I feel that if I solved my millisecond problem, this would work the way I intended.

    In the original example the loop would take 5 milliseconds to execute, but I wished the loop to execute once every 20 milliseconds or 50Hz. (ignore the constant, it is unused). First I calculate the elapsed time then calculate the remaining time to make up the 20 millisecond loop time. Then I use the pause function to block the cog for the remaining milliseconds. It seems to me that this is what the pause is for.

    Please explain my misunderstanding of the pause function.

    Thanks again,
    Doug
  • doug.taylordoug.taylor Posts: 31
    edited 2014-07-28 05:43
    All,

    In my previous post, I state that my problem may be that the implementation of time_t only contains whole seconds and cannot be used with difftime to produce fractional seconds. If this is indeed the case, I will need an alternate solution.

    While researching for the previous post I stumbled upon the Millisecond Timer Library written by Andy Lindsay. I wish I had found it earlier. Would this be the definitive solution? If so, I have a question about its use.

    https://propsideworkspace.googlecode.com/hg/Learn/Simple%20Libraries/Utility/libmstimer/Documentation%20mstimer%20Library.html

    The documentation says "Additional calls to mstime_start will only shut down and then re-launch the process". In my project I wish to have two different loops running in two different cogs. One loop I wish to run at 50Hz and the other at 100Hz. The code in each loop measures how long the loop takes and subtracts that value from the length of time the loop is supposed to take to get a pause time. If I understand the documentation, I cannot use this library for both loops. Is this assumption correct? Is there a work around?

    Thanks,
    Doug
  • ersmithersmith Posts: 6,054
    edited 2014-07-28 06:32
    time_t holds only whole seconds (as is in fact customary in most systems), so difftime will return 0 for elapsed time less than a second. The reason difftime returns a double is to ensure that it has sufficient range on all systems (remember the C standard is specified for all kinds of computers, including 16 bit computers).

    The simplest way to time short intervals on the propeller is to read the variable CNT, which is defined in <propeller.h> and holds elapsed system ticks. You can convert this to seconds if necessary by dividing by your Propeller board's frequency (typically this is 80_000_000, but your mileage may vary).
  • doug.taylordoug.taylor Posts: 31
    edited 2014-07-28 09:05
    ersmith wrote: »
    time_t holds only whole seconds (as is in fact customary in most systems), so difftime will return 0 for elapsed time less than a second. The reason difftime returns a double is to ensure that it has sufficient range on all systems (remember the C standard is specified for all kinds of computers, including 16 bit computers).

    The simplest way to time short intervals on the propeller is to read the variable CNT, which is defined in <propeller.h> and holds elapsed system ticks. You can convert this to seconds if necessary by dividing by your Propeller board's frequency (typically this is 80_000_000, but your mileage may vary).

    ersmith,

    Thanks for the reply. This looks encouraging. I was afraid to use CNT because I didn't know the frequency. How would one determine the correct value? Empirically, by testing?

    Doug
  • ersmithersmith Posts: 6,054
    edited 2014-07-28 11:19
    Thanks for the reply. This looks encouraging. I was afraid to use CNT because I didn't know the frequency. How would one determine the correct value? Empirically, by testing?

    It should be in the documentation for your board. Generally, as I mentioned, 80 million is the default; only a few specialized boards do things differently (e.g. some people "overclock" to 100 MHz). Also note that you can change the settings of the clock at run time; if you do so, the frequency will change.
  • doug.taylordoug.taylor Posts: 31
    edited 2014-07-28 15:41
    ersmith,

    Thanks for all your help. I now have a pattern for any timed loop.
    /**
     * This is the main TestLoopDuration program file.
     */
    
    #include "simpletools.h"                      // Include simple tools
    #include "stdbool.h"
    
    // Constants
    static volatile const int _HZ_ = 50;
    static volatile const double _TICKSPERMILLISECOND_ = 80001.5; // empirically determined
    
    // Function prototypes
    void LoopController();
    void LoopContent();
    
    int main(void)
    {
      LoopController();
    }
    
    void LoopController()
    {
      double loopTime = 1000 / _HZ_;
      int sleepMilliseconds = 0;
      double startCnt = 0.0;
    
      while(1)
      {
        //  get a timestamp at the beginning of this loop
        startCnt = CNT;
    
        LoopContent();
    
        // get the time to sleep
        sleepMilliseconds = (int)(loopTime - ((CNT - startCnt) / _TICKSPERMILLISECOND_));
        if (sleepMilliseconds > 0)
        {
          pause(sleepMilliseconds);
        }
      }
    }
    
    void LoopContent()
    {
      // do some time taking tasks
    
      print("  loop content\n");
      pause(5);
    }
    
    
  • doug.taylordoug.taylor Posts: 31
    edited 2014-07-31 14:20
    Update:

    I now have a version that only uses ticks:
    /**
     * This is the main TestLoopDuration program file.
     */
    
    #include "simpletools.h"                      // Include simple tools
    #include "stdbool.h"
    
    // Constants
    static volatile const int _HZ_ = 50;
    static volatile const unsigned int _TICKSPERMILLISECOND_ = 80002; // empirically determined
    
    static volatile int cntr = 1;
    
    // Function prototypes
    void LoopController();
    void LoopContent();
    
    int main(void)
    {
      LoopController();
    }
    
    void LoopController()
    {
      long stopTicks = 0;
      long waitTicks = 0;
    
      while(1)
      {
        //  get a stop time at the beginning of this loop
    //    unsigned int loopLengthMilliseconds = 1000 / _HZ_;
    //    unsigned int loopLengthTicks = loopLengthMilliseconds * _TICKSPERMILLISECOND_;
    //    stopTicks = CNT + loopLengthTicks;
        stopTicks = CNT + (1000 / _HZ_ * _TICKSPERMILLISECOND_);
    
        LoopContent();
    
        // get the number of ticks to wait
        waitTicks = stopTicks - CNT;
        // if that number is positive
        if (waitTicks > 0)
        {
          // add it to the current count and wait
          waitcnt(CNT + waitTicks);
        }
      }
    }
    
    void LoopContent()
    {
      // do some time taking tasks
    
      cntr++;
      if (cntr > 25)
      {
        cntr = 1;
      }
      pause(cntr);
    }
    
    
  • jazzedjazzed Posts: 11,803
    edited 2014-07-31 14:29
    Looks reasonable.

    The file propeller.h also has waitcnt2().
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-08-05 11:43
    jazzed wrote: »
    Looks reasonable.

    The file propeller.h also has waitcnt2().


    WAITCNT (using the generic term here) is perfect for fixed-frequency loops; seems like it should have been the first choice.
Sign In or Register to comment.