Pause()

Discussion about the ZBasic language including the System Library. If you're not sure where to post your message, do it here. However, do not make test posts here; that's the purpose of the Sandbox.
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Pause()

Post 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?
Tom
mikep
Posts: 796
Joined: 24 September 2005, 15:54 PM

Post 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).
Mike Perks
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post by GTBecker »

Why does Pause(1) take 1.953mS?
Tom
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post 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
Tom
mikep
Posts: 796
Joined: 24 September 2005, 15:54 PM

Post by mikep »

GTBecker wrote:Why does Pause(1) take 1.953mS?
Don't know. We will have to wait for Don :)
Mike Perks
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post 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.
Tom
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post 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().
- Don Kinzer
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post 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.
Tom
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post 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.
- Don Kinzer
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post 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.
Tom
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post 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
- Don Kinzer
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post 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)
Tom
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post 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.
- Don Kinzer
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post 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.
Tom
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post 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?
Tom
Post Reply