We are calling nanospin() function with count value for 10usec in interrupt handler for int 0(tick interrupt). we used InterruptDisable(), InterruptEnable functions before we call nanospin. we called nanospin_calibrate() once before attaching inetrrupt handler.
Used port80 debugging for checking the accuracy of nanospin. But found that, the spin count is never the same, every tick.
There is a variation of maximum 2usec.
We need timings to be accurate for our application.
We used assembly instructions to generate this in QNX4. But for portability reasons we deviated from assembly. In QNX4, we did not see this amount of variation.
Is there a way we can get around this, Or assembly is the best solution?
I report this, because it can easily be overlooked. Did you mean an Intel P1? I don’t know of an Intel P1 processor that had a “supervisor” mode, but there were integrated P1 type processors that did. What is the point? A processor with supervisor mode turned on is inherently non-real-time. Even with interrupts turned off, the supervisor mode can take over and leave you wondering where the cycles went.
yes it is Intel P1 processor. But with QNX4, we used assembly instructions to get the delay. We also used sti, cli instructions before and after. But the variations was not so much.
With QNX6, for portability, we used QNX6 API for delay. Not aware of this supervisory mode.
Both software are running on same processor card. But could see the variations more in QNX6 comaparatively.
Could you provide source code? I would like to see if you call nanospin() from ISR or interrupt handling thread. Also, it’s interesting to see how exactly you measure. 2 us sounds a way too much, looks like you have some context swithing involved.
As you can see there is no black magic in there. Just a simple loop.
You might try to call nanospin_count instead of nanospin(). You just need to use nanospin_ns_to_count to obtain the value to pass to nanospin_count ( I would do it outside of the interrupt ).
I got down to the assembly code ( via gdb ) because I wanted to see if there wasn’t something in there that would re-enable interrupt as it would have explain the jitter you are seeing.
I didn’t completely follow the code from nanospin() down to nanpspin_count, so there could be something that re-enable interrupt (though I doubt it). If you use nanospin_count though that will rule this possibility out.
Depending on the cache state nano_spin_ns_to_count could have different execution time, it’s a rather long function and it uses a divide instruction. I’m not convinced it could explain the 2us variation thought.
We were trying to measure assembly timings using the code below.
But we are facing some compilation issue with outb calls. it gives the
error as below, for code
asm(" movb $0x80, %dl;
movb $0x01, %al;
outb %al, %dl"
:
:
);
cc -o firectrl2501 firectrl2501.cc
{standard input}: Assembler messages:
{standard input}:33: Error: suffix or operands invalid for `out’
cc: /usr/qnx630/host/qnx6/x86/usr/bin/ntox86-as error 1 Checked some
sites, outb seems to be correct instruction?
Since assembly is found comparatively better, we are planning to build delay loops in assmebly instead of nanospin.
I have no experience with assembler on QNX 6, but something jumps out immediately.
outb al,dx → output a byte from the 8 bit al register to an 8 bit port
outw ax,dx → output a two byte value from the 16 bit ax register to a 16 bit port
outb al,dl → this is not part of x86 asm.
In all cases, the port number is put in the DX register, not the DL register.
outp instruction often tends to make the time of assembly code more “stable”. The reason is that quite often port 0x80 in this example is assume to be on the ISA bus, hence the CPU will have to slow down to the speed of the ISA bus while performing that instruction. That makes the instruction incredibly long compare to other instruction and help reduce effect of cache.