Timer / RtosTimer accuracy and details ?

10 Feb 2014

Hello there,

we are using a mbed 1768 module for a data processing application where we need a precise cycle of 1 ms. So we used an RtosTimer to call our routine in 1 ms cycles. We checked the accuracy using a scope and by reading a µs-timer, so far without problems.

In our RtosTimer-callback-routine we read a Timer.read_us() value and check the time difference to the previous call, since our software usually needs 13 or 14 cycles to compute final data, we usually read values of 13000 or 14000 µs, with a deviation of only 5 to 10 µs - which is good.

Now we were collecting these time differences over a period of a few minutes and found strange deviations: some every 23 seconds, our time stamps - which should be a factor of 1000 µs - shows a random deviation, like 14325 µs, the next cycle with 14625 µs etc. and after that, the time diff is again precisely 13000 or 14000.

We were trying to find details on how RtosTimer... and Timer... work in detail, but we were not able to find anything. I assume that these routine utilize the 1768 timers, but how ?

The behaviour looks a bit like a frequency sweep : it looks like the "sweep" - or whatever it is - occurs every 23 sec, then the "other" frequency would be off by 0.0435 Hz

Now we have two assumptions: 1. if the RtosTimer is accurate 1ms, then the Timer.read_us() reads sometime wrong data 2. if the Timer.read_us() works accurate, then our Rtos callback is sometimes delays

Can anyone help us to understand the details of how these timers work ? thanks in advance Matthias

19 Feb 2014

Ok, since nobody replied, I guess this RTOS implementation is magic and fell from heaven....

In case someone else has similar problems: this is what we found.

We have this one routine that is called frequently based on a RtosTimer with a cycle of 1 ms - this seems to be interrupt based since the accuracy is very good. It seems to be as good as the crystal oscillator is.

Also, the Timer.read_us() seems to be accurate, we haven't found any indication that this information is delayed or is affected by anything else.

Our problems were caused by a criticial run between a UDP receiver thread and the RtosTimerProc: the UDP receiver was activated on an incoming packet, then the RtosTimer interrupt ours, then on the next Mutex access it seems, we returned to the UDP receiver and so on.

For me, working with RealTime and Multitasking systems, the mbed/RTOS documentation is really poor because I'm missing all the important informations on how thread changes will happen, if this is a pre-emptive or cooperating system and much more - ok, if someone can point me to a proper documentation I really appreciate it,

19 Feb 2014

Don't know how much it will help you, but the mbed RTOS is an interface around RTX. So some documentation: http://www.keil.com/support/man/docs/rlarm/rlarm_ar_artxarm.htm

19 Feb 2014

As you've suggested, this is likely due to a thread priority configuration. The RTOS Thread documentation says that the RTOSTimer runs in the osTimerThread. I couldn't find any API that allows configuration of that thread's priority. I dug through the mbed-rtos source and found that it looks to be hard-coded at High priority. It looks like the highest priority available is one step above High at Realtime. I don't think the mbed RTOS is truly preemptive. Maybe someone else can confirm this.

So, for a RMS (rate monotonic sheduling) algorithm, you would like to give this thread a higher priority corresponding to its execution rate. It doesn't appear to be possible using the RTOSTimer as written.

Is there a reason you can't use a regular RTOS Thread? Then, you can explicitly set the priority. The downside is that you may not get a cycle of 1 ms exactly, since you'll have to use Thread::wait(1). Your processing overhead will add to the 1 ms (the resolution is 1 ms). Or, lower the priority of the UDP thread. But, you didn't give any details about that. Just something to think about.

20 Feb 2014

Hello Erik and David, thank you for the reply, I will check the RTX documentation as soon as possible.

David, your explanations really make sense and it matches what I experience. Using this RTOS is to me like black-box-debugging.

I wouldn't use a regular thread because our application is sort of a measurement device, and our output needs to run on a precise 1 kHz (as good as the crystal is, which seems to be of an acceptable accuracy). The reason is that we receive data in a "x" millisecond cycle from one system and our output goes to a third device that also expects data in a millisecond cycle. A wait() would cause an additional delay which is not acceptable here.

David, I like to ask one more thing: I was trying to dive into the mbed-source, too, I mean the sources that are part of my project (I still use the online compiler): are these sources complete ? What I like to say is, is this all open source, or is there still some pre-compiled library code that I'm not able to see, but which is linked into my binary ?

I changed now the way our data is internally processed: incoming data is only fed into a queue and then I do all the math work in the RtosTimer-Proc, depending on which flags are set and which queue delivers data, and this works well so far.

But I ran into a new problem: it seems that my RtosTimer is delayed every so many seconds, the frequency is not regular, but this delay is in the range of 10-50 ms. I detect the delay, because I label all my outgoing data with a microsecond time-stamp.

Since I'm using "Queue" things, which seem to implement some dynamic memory access, do you think there is something like a garbage collection, de-fragmentation or whatever ?

thanks for your ideas, matthias

20 Feb 2014

You could also use a 1kHz ticker interrupt, during which either the measurement is done, or a signal is set for a high priority RTOS thread which then does the measurements. I would have no idea where your new delay is coming from, but I doubt it is garbage collection.

The RTOS back-end is precompiled, you cannot see the source. The mbed-src library is complete: it is all open source and contains all source code, nothing precompiled there.

Ran a quick test using:

#include "mbed.h"
#include "rtos.h"
 
Timer timey;
volatile int previous;
 
void blink(void const *n) {
    int cur_time = timey.read_us();
    printf("Took %dus\r\n", cur_time - previous);
    previous = cur_time;
    
}
 
int main(void) {
    RtosTimer led_1_timer(blink, osTimerPeriodic, (void *)0);
    timey.start();
    
    led_1_timer.start(400);
    
    Thread::wait(osWaitForever);
}

Not 1 ms, I tried that first, but that wasn't one of my smarter ideas, trying to output at 1kHz to serial terminal. The first one is 3us too long, the second 1us too short, after that all exactly correct.

Since it might be compensating each other (some 20us too long, others 20us too short, I also ran a simple check where it only prints errors:

#include "mbed.h"
#include "rtos.h"
 
Timer timey;
volatile int previous;

Serial PC(USBTX, USBRX);
 
void blink(void const *n) {
    int cur_time = timey.read_us();
    if ((cur_time - previous > 1001) || (cur_time-previous < 999))
        PC.putc('E');
    previous = cur_time;
    
}
 
int main(void) {
    printf("Start\r\n\n");
    RtosTimer led_1_timer(blink, osTimerPeriodic, (void *)0);
    timey.start();
    
    led_1_timer.start(1);
    
    Thread::wait(osWaitForever);
}

Since the LPC1768 has a FIFO on its serial (without the proper registers to really use it correctly though), this goes fine as long as the number of errors is limitted, if it runs out of space on the FIFO it will need to wait until the character is sent, resulting in a too long period, etc. This prints a single 'E' for me. If I check if it is larger or smaller than 1000 (ie, not exactly 1000), it does write alot of 'E's. But that is really nitpicking. So to me it looks like the basic functionality of the timer works fine. So then it looks to be related to your other code. (That the first ones aren't exaclty what is expected is correct btw, since it starts the timer first, and then the RTOS timer, so the first measurement includes overhead from the RTOS times start. And not to mention that the previous time is unitialized, so it might be 0, might be something else).

20 Feb 2014

Matthias,

Regarding the mbed RTOS source, I had to do a bit searching. What I ended up doing was using the Import wizard, then search for mbed-rtos in the search dialog. Select the Offical mbed library and import it to a folder in your Workspace. After that, you should have access to all the RTOS source code. It is licensed under the Apache 2.0 license that mbed uses. You can also find it at http://mbed.org/users/mbed_official/code/mbed-rtos/, but I prefer looking at code in the mbed online IDE rather than as web pages. I believe you could modify the osTimerThread priority and build with your app to see if that might work. I've used the RTOSTimer, but not at the high execution rate of your app.

I agree with Erik that I don't think there is any garbage collection going on. Like Erik, I also thought you might look into running a Ticker, but I assumed you didn't already because of the restrictions (it runs in an ISR).