Page 1 of 2

Pause()

Posted: 28 September 2009, 13:48 PM
by GTBecker
Don, of the parameter, the Pause() documentation description says "The amount of time to pause, in seconds (Single) or Timer 0 ticks (int16)" but the example and routine description, I believe incorrectly, suggest that its resolution is 1/230400Hz. Testing suggests that it is, indeed, running at the 512Hz tick rate.

Is the documentation incorrect, or is this a bug?

Posted: 28 September 2009, 14:56 PM
by mikep
The documentation is correct but I had to read it twice to fully understand it.

Timer0 ticks are indeed every 4.34 us. 450 of these Timer0 ticks makes one RTC tick which is 1/512 of a second. Sleep and Delay use RTC ticks whereas Pause uses Timer0 ticks. Task scheduling happens every RTC tick.

The maximum pause length is 65535 * 4.34us = 284,422us (or roughly 284ms as documented).

Posted: 28 September 2009, 16:09 PM
by GTBecker
Why does Pause(1) take 1.953mS?

Posted: 28 September 2009, 16:43 PM
by GTBecker
Try this, with both Pause() and Sleep(), with identical results:

Code: Select all

Sub Main()
	do
		pause(512) 
		Console.WriteLine("Tick " & cstr(register.RTCTick))
	loop
End Sub

Posted: 28 September 2009, 17:06 PM
by mikep
GTBecker wrote:Why does Pause(1) take 1.953mS?
Don't know. We will have to wait for Don :)

Posted: 28 September 2009, 18:07 PM
by GTBecker
Unless Heisenberg is at work (quite possible in a multitasking environment), my ElapsedTime tool shows that Pause(int16) is indeed more accurate and consistent than is Sleep(int16), but it is not more resolute, as the documentation suggests. The long-term mean of both is identical, in ~1.953mS increments according to the int16 value. The example of Pause(2304), which the comment says it equivalent to Pause(0.01), appears to not be correct.

Pause(single), though, does resolve better than Sleep(single). Pause(0.010) shows a spread of ~4.34uS, while Sleep(0.010) shows a spread of about four times that. Pause(single) does it better, but both still round (low) to the nearest tick, ~9.77mS. Pause(0.010) does not produce a 10mS delay despite its faster timebase.

Pause(0.010):
Max= 9.767794E-03S, Min= 9.763454E-03S, Spread= 4.339962E-06S, Mean(5000)= 9.765765E-03S (102.3985Hz)

Sleep(0.010):
Max= 9.771591E-03S, Min= 9.7564E-03S, Spread= 1.51908E-05S, Mean(5000)= 9.765449E-03S (102.4018Hz)

Overall, both forms of Pause() look faulty to me.

Posted: 28 September 2009, 20:17 PM
by dkinzer
Mike is correct in that the units of Pause() are low level ticks of the RTC timer which runs at 1/64th of the CPU frequency or 230.4KHz. The RTC timer is set up to generate an interrupt every 225 of these ticks (yielding an interrupt rate of 1024Hz). The RTC tick value is updated every other interrupt yielding an RTC tick rate of 512Hz.

I'll have to check the performance again using a logic analyzer but the last time I did so the timing was spot on.

One difference between Sleep() and Pause() is that another task may run if you call Sleep() but not so with Pause().

Posted: 29 September 2009, 12:52 PM
by GTBecker
dkinzer wrote:... the units of Pause() are low level ticks of the RTC timer [at] 230.4KHz...
The source, yes, but not the parameter units, which appears to be RTCTicks.

Posted: 29 September 2009, 17:11 PM
by dkinzer
GTBecker wrote:[...] but not the parameter units, which appears to be RTCTicks.
Consider this program:

Code: Select all

Const pin as Byte = 13
Sub Main()
	Call PutPin(13, 1)
	Register.PortA = &H00
#if 1
' Call Pause(23)      ' yields a 119uS pulse
' Call Pause(115)     ' yields a 536uS pulse
  Call Pause(230)     ' yields a 1.034mS pulse
#else
' Call Pause(100e-6)  ' yields a 119uS pulse
' Call Pause(500e-6)  ' yields a 536uS pulse
  Call Pause(1e-3)    ' yields a 1.034mS pulse
#endif
  Register.PortA = &H80
End Sub
This test code was compiled for and run on a ZX-24a. The times indicated in the comments are the length of time that the output pin (pin 13 in this case) was low as measured with a logic analyzer. The resulting pulse times are longer than requested due to the overhead of preparing to pause. (Offhand, I don't know why it is shorter with the approximate 100uS pause than it is for the 500uS and 1mS pause.) Clearly, this demonstrates that the "units" value for Pause() is approximately 4.34uS (as documented) corresponding to the rate at which the RTC timer is clocked.

The integral values to pause in the first #if section correspond to the values that the compiler generates for Single constants in the second section (which you can verify by examining the .lst file).

Using the same test on a native mode device reveals an implementation error that was previously undetected.

Posted: 29 September 2009, 18:38 PM
by GTBecker
dkinzer wrote:Using the same test on a native mode device reveals an implementation error...
I have been developing and testing on a ZX-24n so I expect that we will both be found right. Thanks for pursuing it.

Posted: 30 September 2009, 13:02 PM
by dkinzer
dkinzer wrote:Using the same test on a native mode device reveals an implementation error that was previously undetected.
This issue has been corrected in the experimental release of the compiler and ZX Library (both are required).

Compiler:
http://www.zbasic.net/download/ZBasic/2 ... 2-8-10.zip

ZX Library:
http://www.zbasic.net/download/zxlib/zxlib_2-7-5.zip

Posted: 30 September 2009, 13:55 PM
by GTBecker
Pause is better, but the spread (jitter) is much greater. The previous compiler and library yielded 4.4uS spread (around an RTCTick); the new is ~9 times greater, but around the correct period.
  • Pause(0.010), Previous compiler version on ZX-24n:
    Max= 9.767794E-03S, Min= 9.763454E-03S, Spread= 4.339962E-06S, Mean(5000)= 9.765765E-03S (102.3985Hz)

    Pause(0.010), New compiler (v2.8.10) on ZX-24n:
    Max= 0.010096S, Min= 0.0100564S, Spread= 3.960448E-05S, Mean(5000)= 0.0100791S (99.21557Hz)

Posted: 30 September 2009, 14:28 PM
by dkinzer
GTBecker wrote:Pause is better, but the spread (jitter) is much greater.
You may be able to reduce the spread by adding some synchronizing code. For example, if you loop waiting for a change in Register.RTCTick you may get within a few cycles of starting a sequence at the same phase relative to the cycle of the RTC timer.

Posted: 30 September 2009, 19:23 PM
by GTBecker
It is interesting that the timing spread of Pause() now is almost always ~43.4uS (4.34uS*10, of course), sometimes one tick less, 39.06uS. I guess I was spoiled by the perhaps artificially-low one-tick 4.34uS spread when the function was misbehaving, implicitly synchronized to the RTCTick, as you suggest. Still, it produces very good timed delays now.

I tried several values I thought might be practical, like a half-cycle of 60Hz:
  • Pause(0.008333) on a ZX-24n:
    Max= 8.428818E-03S, Min= 8.385415E-03S, Spread= 4.340241E-05S, Mean(5000)= 8.40876E-03S (118.9236Hz)
That's about 9.1% long.


One-quarter second:
  • Pause(0.25):
    Max= 0.2500911S, Min= 0.2500564S, Spread= 3.47197E-05S, Mean(50)= 0.2500778S (3.998755Hz)
+0.03%

A quarter-second using Sleep():
  • Max= 0.2500044S, Min= 0.2499957S, Spread= 8.687374E-06S, Mean(50)= 0.25S (4.0Hz)
The apparent error here is essentially zero since the timing mechanism and the timed object are based on the same timebase. [Strictly, everything in the machine is based on the same timebase, but the ~asynchronous nature of Pause() makes it less precise than exact multiples of the RTCTick, as 0.25S is, I think.

It should be very handy for odd, short periods.

Posted: 14 March 2010, 14:28 PM
by GTBecker
I'm having some difficulty with Pause, again, and I'm having trouble building a simple demonstrable case.

In some code, a ZX-24n behaves as if it interprets the Single-type parameter as Timer0 clocks in the following, instead of real time:

Code: Select all

    call Pause(ArmDelay)	' value is in Seconds

Code: Select all

    call Pause(cint(230400.0 * ArmDelay))	' converts period to Timer0 clocks
The former delay is far too short; the latter call yields the correct delay. If I simply extract this code and try to make a test case the procedure works fine, though, interpreting the Single parameter correctly as real time.

What might affect how the IDE interprets the parameter type here?