Imp.wakeup timer inaccuracy solutions

Hi, all. I’m hoping somebody has a workaround for how inaccurate imp.wakeup is at timing events.

For example:

`toggle <- hardware.pin8;
toggle.configure( DIGITAL_OUT );

toggleState <- 0;

function test()
{
toggleState = 1 - toggleState;
toggle.write(toggleState);

imp.wakeup( 0.01, test );

}

test();

`

Shouldn’t the above loop at approx 100 Hz? While I realize imp O/S has some overhead, the actual frequency of this loop is closer to 50 Hz, as measured by my logic analyzer hooked up to pin8.

Further tests show this:

imp.wakeup(x) / Measured Loop Speed
0.1 (10 Hz) / actual = 9 Hz
0.05 (20 Hz) / actual = 16 Hz
0.02 (50 Hz) / actual = 33 Hz
0.01 (100 Hz) actual = 49 Hz

The first two results aren’t too bad, but the last two are way out to lunch.

Are others seeing the same? Am I doing something wrong?

If not, what means is there to accurately fire regular events off at a known fixed frequency? imp.wakeup sure ain’t it…

Thanks.

I would suggest using a PWM output set to the required period. Set it going and leave it. You can even choose whether the period needs to be exact, or the mark/space ratio.

This is because the imp runs with a 100Hz ticker, and specifically attempts NOT to call a timer early. You can improve this slightly by moving your wakeup to the start of the callback, so that the time spent executing the ping toggle is not causing the wakeup to drift each cycle.

As DrJack says, if you want accurate timing, use a PWM which is hardware-timed.

Thanks, guys, but how does that help? The “event” that I want to occur at a known frequency is a function, not flashing an LED or something. I see no provision within the PWM API for a callback.

Can you say a bit more what the “event” is? Given that the CPU is sometimes busy doing things like TCP and TLS, accurate timing doesn’t happen with the CPU - but here your problem appears to be more to do with the 100Hz ticker frequency that wakeups are scheduled with.

Is there an external trigger? A pin change handler obviously doesn’t depend on timers (just the actual pin transition). You could always set up a PWM output with the required frequency, then loop this pin back to a pin with a change handler on it.

Yes, I considered physically wiring something into a pin change handler. Seemed like too crude a hack to pursue if another way is possible.

Imagine A = B + C, where B and C are relatively involved functions. Each takes input from real-time data streams: one a changing voltage, the other a serial data stream (requiring parsing). But, I want A to be output at a known, fixed rate, independent of how long either B or C takes.

I want to produce code that plays nice. Besides producing A as output, my code also has other responsibilities, so I don’t simply want A to be produced as fast as possible. That hogs CPU cycles unnecessarily from these other tasks, including the O/S itself.

So, I’ve come up with the following way to throttle things in lieu of imOS not being multi-threaded in nature. Not sure it’s the best way. Say I’m happy with an A update rate of P /sec, my process frequency, P (say, 200 Hz). A must output 200x/sec, or close to it. I have B produced by imp’s Sampler feature at 2000 Hz. 10x oversampling. All good so far. C is busy parsing the serial stream for validly framed data (which it may or may not find). That’s called via a wakeup timer Bx/sec (not really, though). Each continuously updates a global table with their results. I know B and C each take less time to complete than their respective periods. Then, A (via imp.wakeup( 1/P, A) simply polls the table and does its stuff.

This all seems to work quite well. I can partition the CPU costs by adjusting the callback and wakeup frequencies to achieve whatever real-time responsiveness I require. At least, if wakeup didn’t hit the snooze button so much…

So, now do you see where I’m stuck? Even though imp.wakup has centisecond resolution, it can’t fire things more often than 50x/sec, and, regardless, is not the best way to provision the above anyway, me thinks.

Even if I changed C to a uart event-based model, I can’t get A to fire at 200x/sec (or even 60x/sec for that matter).

Maybe try this type of thing:

`count<-0;
function idletask() {
local now=hardware.millis();
if (now>=next) {
count++;

    // Run again in 10ms
    next=now+10;
}

// re-queue ourselves for next time we're idle
imp.onidle(idletask);

}

next<-hardware.millis();
idletask();

imp.wakeup(1, function() { server.log(“count=”+count)});
`

…essentially, this is just using onidle() to run a low priority task; it’ll be executed after any other event handlers (eg for B’s UARTs). At some point we’ll transition to our tickless OS and then you should get better resolution for your callbacks (I think: Peter is the one who really knows how this will work and I’m just guessing).

I truly think something like that’s the only way. Thanks very much for giving me some ideas.

I do wish the imp had a general timer with callback, though. Much could be done with it. Though, I can imagine that is intentional to protect the OS in its current form.

Give the sampler a large number of 10-sample blobs and use its callback as the timed function? In other words, arrange that B is available 200 times per second, and each time it is, check whether there’s a C. Although you may find that the latency doing that is too much; if it is, you’ll get sampler overruns.

Peter

Thanks, Peter. Another creative option. I appreciate your help.

So, we’ve got: PWM wire-back, hardware.millis, and Sampler-overloading. I’ll see what works best of the latter two (no free pins for option 1).

Thanks all.