Timer in developed app running slow on Forerunner 935

Hi everyone, 

I have recently developed a fitness test app with timings for several "beep test" like exercises. However, I have had a user using a Forerunner 935 complain that the timer runs slow on their watch - for example, an interval that is meant to take 15 seconds takes about 28 seconds to count down from 15 to 0.

I have tested this in the 935 simulator (as well as a number of different device simulators) and this behaviour is not present. I have also tested it physically on a FR945, FR245, and a Vivoactive 4 and it all appears to be fine. 

Has anyone else experienced such behaviour on the FR935?

I suspect that the timer call back in the app is perhaps operating at a lower speed, but it is the same for all other devices and I do not know why this particular user is experiencing this. The timer callback should run every 50 milliseconds. 

Thanks

Top Replies

All Replies

  • Are you using a one shot or repeating timer? The doc implies that repeating timers can have skipped executions:

    developer.garmin.com/.../Timer.html

    If a repeating Timer fails to run before its next execution time, then any missed executions will be skipped.

    Maybe it's also possible that either a one-shot or repeating callback could be delayed (due to other stuff going on in the system, or even due to the amount of time your callback takes to execute.)

    Either way I probably wouldn't try to rely a timer callback being fired after *exactly* the specified amount of time. e.g. If you have a 50 ms timer which repeats, I wouldn't assume that when it fires 20 times, exactly 1 second has passed.

    For example I have a stopwatch app that uses a 50 ms one-shot timer to update the screen, but I don't assume that 50 ms actually passed between the scheduling of the timer and the timer callback. I use System.getTimer() to determine the elapsed time between any two "events" (like starting the stopwatch and displaying the current stopwatch value). That method should be pretty foolproof.

    e.g.

    var startTime;
    var timer = new Timer.Timer();
    
    // call this when the user presses START or whatever
    function initializeTimer() {
      startTime = System.getTimer(); //get the uptime in milliseconds
      onUpdate();
    }
    
    function scheduleUpdate() {
      timer.start(method(:onUpdate), 50, false);
    }
    
    function onUpdate() {
      var now = System.getTimer();
      System.println("The current timer time is " + (now - startTime) + " ms");
      
      // Update the screen, etc
      
      scheduleUpdate();
    }

  • Great answer, thank you. It is a repeating timer. I have both my screen update and timer decrement (subtracting 0.05 seconds for each callback from the time remaining variable) all in the callback, so it is almost certainly the case that executions are being skipped and the timer is not decrementing properly.

    So it sounds like updating the screen using a callback is fine, however, what would you suggest for managing the duration of each interval? For example, if an interval requires to be exactly 9.5 seconds, and we can't rely on the callback being run every 50ms, should I perhaps use a one-shot timer for each interval, to ensure that it runs for the full 9.5 seconds?

    Thank you

  • For example, if an interval requires to be exactly 9.5 seconds, and we can't rely on the callback being run every 50ms, should I perhaps use a one-shot timer for each interval, to ensure that it runs for the full 9.5 seconds?

    I don't think so, especially given the fact that I'm sure you have to update the screen more often than once per 9.5 seconds anyway.

    What I would do is have an update function that updates the screen, checks the current interval time and does any of the work that needs to be done when the interval/activity time changes. You would run the update roughly every 50 ms by using a timer which is started after you do all your work.

    e.g.

    User presses Start:

    - lastTime = System.getTimer()

    - startTime = lastTime

    - activityTime = 0

    - intervalTime = 0

    - call onUpdate()

    onUpdate():

    - now = System.getTimer()

    - deltaTime = now - lastTime

    - activityTime += deltaTime

    - intervalTime += deltaTime

    - elapsedTime = now - startTime

    - lastTime = now

    - Update screen with with intervalTime, etc.

    - if (intervalTime >= 9500) onInterval()

    - Use Timer.Timer to schedule next onUpdate() in 50 ms. (Or maybe 100 ms - 500 ms, depending on how you want to balance battery life and timer precision. Consider that a data field app only runs compute() roughly once per second)

    onInterval():

    - intervalTime = 0

    - do whatever

  • I can see where 50ms could be too fast and you'll miss some.  Recall CIQ is single threaded, so if you have something that runs longer than 50ms, the timer won't fire during that time. 50ms really isn't that long, where the power budget for onPartialUpdate (updating a small part of the screen in a watch face) is 30ms.

    What happens if you set a longer timer? say 100ms, 250ms, or 500ms?

  • Thanks for that Jim. I've set it to 250ms, as all this timer is used for is updating the screen, which definitely does not need to be done every 50ms.