usleep problem

Weez
Hi guys,

I ran into a very strange problem. I have a C program which has a for loop
and a usleep(100000) on the end, to execute this loop in 10 times per
second. After I've measured the whole seconds delay in comparison with a
usual handheld stopper it turned out, that the seconds on my mini2440 are
slower than on a real clock - in a 45 seconds period I had a 10 seconds
difference!

The loop execution time using gettimeofday() takes something about 0.000006
seconds, so I don't think it's the content of the loop.

How can I fix this?

Ceiliedgh
usleep doesn't guarantee that your application will sleep for exactly
100000 nsecs, it guarantees that it will sleep for *at least* 100000 nsecs.

The actual time depends on the kernel clock tickrate, so a small difference
in timing is expected, but 10sec sounds a bit extreme.

Did you try measuring the difference using the RTC on the mini2440?
Its clock source is completely separate from the CPU core signal, so if the
difference is really there the RTC and expected time should differ too.

Perhaps you should also try and run a sleep(45) in a parallel thread (or
something); if both sleeps are delayed by ~10 secs, then it's most likely a
kernel issue (miscalculated HW timer freq); otherwise i suspect the kernel
call overheads and timer imprecision slowly adds up.

Weez
Thanks Ceiliedgh,

I tried to test the RTC with the test program which is given here:
http://kernel.org/doc/Documentation/rtc.txt but I get some strange errors.

The hwclock runs fine, /dev/rtc is also present, but in /proc/interrupts
there is no information about the RTC. Seems like the RTC is not giving any
IRQs? The test program gives me this error: "RTC_UIE_ON ioctl: Invalid
argument" - I have not even the slightest idea why this happens.

Is this because of a kernel config or is the error caused by something
else?

Ceiliedgh
The RTC_UIE_ON stuff isn't an issue I think. This is from the s3c RTC code:

324         case RTC_UIE_ON:
325         case RTC_UIE_OFF:
326                 ret = -EINVAL;

So I think UIE_ON its not supported for the S3C2440.


Having 0 interrupts for the RTC is normal; the RTC only gives an interrupt
if the RTC alarm registers are set up, otherwise the kernel simply polls it
to read the hw clock.

Weez
Since I am not so familiar with using the RTC (/dev/rtc) in C, I tried to
figure out what amount of time in the usleep command will delay the loop
for exact a 1/10th of a second.

Surprisingly at the amount of 70000 the delay was exactly the 1/10th of a
second. I have checked this at a 15 minutes period with a stopwatch and
there were no time difference.

This is of course the dirty way, to achieve the right delay, but instead of
this solution I would like to use the RTC.

Have any of you guys any example code, how I could use the RTC as a 1/10th
sleep timer?

Thank you very much!

Ceiliedgh
AFAIK the RTC doesn't have subsecond resolution (so it only stores seconds,
but not milliseconds), so it cannot be used to sleep < 1 seconds.

If the kernel timers are working properly, you could use something like
this (though it's a bit of a hack):

void sleep_hack(long interval_ms)
{
    struct timespec start_ts;
    clock_gettime(CLOCK_MONOTONIC, &start_ts);
    long start_ms = start_ts.tv_sec * 1000 + start_ts.tv_nsec / 1000000;

    for (;;)
    {
        usleep(1000);
        struct timespec cur_ts;
        clock_gettime(CLOCK_MONOTONIC, &cur_ts);
        long cur_ms = cur_ts.tv_sec * 1000 + cur_ts.tv_nsec / 1000000;
        if (start_ms + interval_ms <= cur_ms)
            break;
    }
}

(untested code, i don't even know if it compiles!)