Electronic – Busy-wait sleep function has incorrect timing on NIOS CPU

cdelayembeddednios-ii

I have a Qsys system which includes a NIOS II/e CPU (which is the only master on the bus) and a 36kB chunk of 32-bit internal RAM. The RAM is configured to have the minimum read latency (which is 1 cycle). The whole system is clocked by a single 50MHz clock.

I'm trying to use the usleep function to wait for 1 second and use clock to measure the time:

#include <sys/alt_stdio.h>
#include <unistd.h>
#include <time.h>

void main(void) {
    clock_t start, end;
    start = clock();
    usleep(1000000);
    end = clock();
    alt_printf("usleep(1s) takes 0x%xms\n", (end - start) * 1000 / CLOCKS_PER_SEC);
}

Surprisingly, I get a value 0x592 (1426 DEC), which is not even close to 1 second. Toggling a pin before and after usleep and measuring the time externally confirms that the delay is indeed close to 1.4s.

I understand that busy-waiting is affected by RAM latency and bus arbitration, which I carefully tried to exclude. What is the expected system configuration on which usleep works correctly? Is there an alternative delay function with μs resolution which would work on the configuration I have?

To answer the clarification request, all durations are wrong by about the same factor (1.4), which I suppose depends on the hardware configuration. Simply multiplying by the corrective factor is not a solution for me, since this is for a project which should allow the users to run Arduino code on any FPGA capable of implementing NIOS.

The usleep implementation I'm using comes from Altera "Small C library", AFAIK it's a clone of newlib. Compiler options from "Hello World Small" sample project reproduce the issue. I tried several combinations of options, and none of them fixed the problem. Again, since this is for a library, I'd like to find a solution which works with different (reasonable) compiler options.

Best Answer

If this is the whole code and not a pseudo code trimmed for this post, it is clear that you have a problem with newlib implementation.

The quick solution is making your own macro using clock()

end = clock() + delay;
while((end - clock()) > 0);