Corruption of "time" variable

afb

Member
I'm using the "time" variable (at 4Mhz) to time periods up to 20 seconds using an 08M2.

Initially I disable "time" immediately following it being detected to have been updated so I when I later start my timer (and enable "time") it gives a complete second upon the first update update of the "time" variable.

Then I start a simple loop that checks when the time variable reaches the target (eg 20 seconds)

In the loop I flash a LED each time the time variable increments and keep two servos refreshed (by "pulsout") so there is also a "pause" statement to govern the loop time to 20mSec. There are also a couple of "IF" statements which are not actioned in a normal timing run.

For testing, I've eliminated my inconsistent reaction times by making an Arduino stopwatch that times to 1/1000 sec and connecting it to a spare 08M2 pin that goes high for the duration of the timing period.

Poor timekeeping accuracy was traced to the inclusion of the "pulsout" commands in the loop which though not 'blocking' like "pulsin" for example presumably access some internal timer register and interfere with the "time" variable as would the "servo" command. The IF, pause and LED driving statements appear to be blameless.

With the Arduino "stopwatch" the native time keeping of the chip (an empty loop) was established to be accurate to about 0.015 sec in a 20 second run. I can add all the other statements without deterioration, but driving a single servo with "pulsout" degrades the accuracy to about 0.15 secs in a 20 sec run, which is just about acceptable in my application. However, adding the second servo gives a disproportionately large error of about 1.5 secs - and I'm at a loss to reason why that is so large.

Instead of using the 'pulsout' command, by flipping a servo output, pausing for two milliseconds then flipping it back I can recover the original native accuracy but now the servos give tiny twitches as these commands sometimes take slightly different times to execute as presumably the chip is doing its own housekeeping in the background. Note that the significant command execution time at 4Mhz means that a 2mSec servo pulse was generated by a high, a dummy high, a 1mSec pause and a low.

Any thoughts, commiserations or alternative ways of skinning the cat are welcomed !

Alan
 

AllyCat

Senior Member
Hi,

The time variable is incremented by a system software interrupt (Timer 1) which "ticks" every 20ms (the same as the dedicated servo output pulses). But PULSOUT (and other commands like PULSIN, SERIN, SEROUT, etc.) need precise software timings so they disable interrupts. Thus the time (prescaler) interrupt can get delayed or lost.

But why are you using PULSOUT instead of the dedicated servo and servopos commands?

Cheers, (another) Alan.
 

afb

Member
Hi AllyCat

Thanks for your reply and the detailed explanation of Timer 1 activity. Over the years virtually all my projects involved reading pulsewidths from RC receivers so even using servopos, jitter still occurred for the reasons that you explain above. Thus I've got into the habit of always using pulsout to ensure stable operation. So with this project (no RC signals to process) I fell into the trap of automatically assuming pulsout was still the way to go.

I am already grateful to you for the trick of disabling "time" immediately after it is incremented such that an asynchronous event like a button press can begin using the time variable knowing that it will always give a whole second for its first 'tick'. However a quick syntax check reveals I'm not allowed to have "disabletime" and "servo" in the same program so I'm back to square one!

Best regards, (a lesser) Alan !
 

AllyCat

Senior Member
Hi,

Hmm, I was aware that DISABLETIME doesn't actually stop Timer 1, but assumed that was so that Servo pulses could still be generated. Therefore, it's surprising that the PE won't allow DISABLETIME with SERVO commands. But AFAIK both are controlled by internal software (not chip hardware) so I doubt if there are any SFR commands to "work around" the problem. :(

Personally, I don't use servos, but can think of two possible solutions. First, you could pair each PULSOUT with a complementary PAUSEUS command (or a dummy PULSOUT). So for example a PULSOUT .. 75 would be paired with a PAUSEUS 225 , or PULSOUT .. 100 with PAUSEUS 200 , etc. to always take 3 ms (plus about 1 ms for the interpreter overhead) regardless of the pulse width.

Another possibility would be to use the hardware PWM outputs, which potentially should suffer no jitter at all. But there are snags: The lowest PWM hardware frequency is too high (~65 Hz), which might be solved by using SETFREQ m2. Also, the PWM has only 1024 steps over the whole period (20 ms) so it could only give a pulse resolution of 20 us (75 steps), not the normal 10 us.

Both those issues might be solved by generating twice as many pulses (i.e. 10ms period) and then "masking out" alternate pulses to the servo (controlled by software). That would probably need two pins per Servo, linked by a simple gate, e.g. two diodes, (I don't think "wired or" could be used with a PWM hardware output pin). There are internal gates like the "Data Signal Modulator" and possibly the "Set-Reset Latch", but they could only gate one PWM signal (each) and the "solution" is getting rather complex.

Cheers, Alan.
 

afb

Member
Hi Alan

Thanks again for your further thoughts. As with most of your other posts you leave me gasping for oxygen!

I understood your hardware PWM approach which I had previously explored for a single servo project but in this twin servo project the 08M2 only has a single PWM output (C.2). Yes at 4Mhz the lowest available frequency is 65Hz but what would the the "time" variable make of 2MHz operation to potentially achieve 50Hz ? Mind you the PWM wizard doesn't admit to 2MHz operation but I expect parameters may be found/calculated for 50Hz. Experimentally I've driven sail winch servos at 100Hz and they are markedly stiffer (the object of the exercise) as they receive error correction pulses twice as often but I'm loathe to make a product operating in uncharted territory for anyone other than myself. Anyhow the die is cast as the PCB has committed to the 08M2 chip (which only has a single PWM pin) and the single PWM pin I have is assigned to a non servo function anyway! For the same PCB reason I couldn't have considered pulsing at 100Hz and masking out alternate pulses with additional hardware. Fortunately I only need to drive each servo with either 1mSec or 2mSec so the pulsewidth resolution you mentioned wouldn't have been an issue.

First, you could pair each PULSOUT with a complementary PAUSEUS command (or a dummy PULSOUT). So for example a PULSOUT .. 75 would be paired with a PAUSEUS 225 , or PULSOUT .. 100 with PAUSEUS 200 , etc. to always take 3 ms (plus about 1 ms for the interpreter overhead) regardless of the pulse width.
This idea has me foxed - quite apart from not following why you are trying to construct a 4mSec pulse, a single PULSOUT has already spoilt my timing accuracy by disturbing Timer 1 so how is adding a further PAUSEUS (that also needs Timer 1) going to to improve the situation? My experience of adding a second PULSOUT for servo #2 crucified the timing accuracy which was just about acceptable when driving a single servo with PULSOUT.

And therein lies my work-around - in this application there is ZERO force applied to servo #2 during the timing period - it simply needs to be set to a start position during initialisation and moved to a finish position when the timed period has elapsed so I can choose not to drive it at all during the timing period and thereby suffer only the marginal timing accuracy deterioration caused by servo #1's PULSOUT. But it would have been nice to have found a 'proper' solution . . . . . . .

Keep taking the clever pills !

Alan
 

AllyCat

Senior Member
Hi,

why you are trying to construct a 4mSec pulse, a single PULSOUT has already spoilt my timing accuracy by disturbing Timer 1 so how is adding a further PAUSEUS (that also needs Timer 1) going to to improve the situation?
Ah, the "1.5 second error" made me think that you were constructing a "precision" 20 ms Servo timing loop (pulse repetition time) in pure software and counting 1000 iterations (for 20 seconds). That could work, but might need a lot of "tweaking". I can't explain why the second servo pulse introduces such a large error; my only guess is that it pushes the interrupts "over the edge" to miss complete "ticks" of Timer 1 and not just stretches the time a little.

A "trick" is to read the Timer1 High byte to see when the next "tick" (overflow) is due to occur (it counts from 178 up to 255 in each 20 ms period). However, reporting/analysing what's happening can be very misleading, because the Serial communications muck up the timing even more than pulsout does. :(

The behaviour of the time variable at all clock frequencies is described in the basic commands tab on the forum. Of course it's not actually a command, but nobody could find it when it was indexed only under LET . ;)

Generally the time variable uses either 2, 1 or half-second ticks at elevated frequencies, but can get very S..L..O..W at frequencies below 2 MHz. :(

Cheers, Alan.
 

afb

Member
Hi Alan

Thanks again for such insightful commentary. Moons ago in 08M days I did try counting precisely tuned lumps of 20 mSec but abandoned it when the 08M2 introduced me to the TIME variable. Also PAUSEUS for fine tweaking was not available then I recall.

I also have a 'sport' version of this 'competition' timer I've been discussing and as timing accuracy is less critical I now realise that I can use the SERVO solution by chucking out "synchronising" the TIME variable (which on average will now give a half second error when the start button is pressed asynchronously) which simplifies matters enormously. This way small errors every time round the 20mSec loop using the PULSOUT method won't accumulate.

I think we can draw a line under this now - thanks again for all your help.

Best Regards, Alan
 

afb

Member
Hi Alan, if you're still there?

"Disgusted of Tunbridge Wells" here !

I've been experimenting with using SERVO for my 'sport' version timer and experimented for much of yesterday with no luck. The only program I could get to run with no occasional twitching (in its minute duration) was as follows

Code:
setfreq m4
servo C.1,100
pause 65000
end
Any attempt at an iterative loop (including DO. . . LOOP, FOR . . . . NEXT or the dreaded GOTO) even just containing pauses in them all fail.

Subsequent extensive trawling through the forum convinces me that greater minds than mine have tried all conceivable tricks to no avail. So I will have to return to the original tried and tested PULSOUT method of servo driving and accept the degradation of timing accuracy, though fortunately I have a work-around that I mentioned in a previous post. Note that I had already painted myself into a corner with chip choice and a stack of PCBs, so was unable to consider some of your other imaginative suggestions!

Best regards

Alan
 

AllyCat

Senior Member
Hi,

Is the PAUSE 65000 a typo, I would expect 60,000 for one minute ? The PICaxe factory calibration is within 1% and can be trimmed to within about 0.1% using CALIBFREQ (+/-31 gives a range of a few percent). The last time I looked, the PICaxe Manual data/comments were badly out-of-date on this issue (see the corresponding Microchip datasheet).

PICaxe instruction execution times are not formally specified and can indeed change whenever the program is edited. But once a program is "finished", the timing should be quite consistent. I'm not quite sure of your requirements but I would try something like the following (semi-pseudocode):

Code:
FOR counter = 0 TO 3000   ; 1 minute at 20 ms per loop (50Hz)
  PULSOUT servo1pin,servo1_pulse    ; Range 75 to 225
  PULSOUT servo2pin,servo2_pulse
  PAUSEUS complementary_delay     ; = 500 - servo1_pulse - servo2_pulse (adjust the 500 as required)
  READ 0, WORD calibration_time     ; Word variable empirically programmed into EPROM
  PAUSEUS calibration_time           ;  About 1400  (14 ms)
NEXT counter
SERTXD ("60 seconds have elapsed")    ; Wishful thinking ?    :-)
I don't believe the system interrupts will add much variation; you could try DISABLETIME but I don't think it affects the interrupts. It might even be possible to stop Timer1 with a SFR command, but things like Watchdog timers need to be considered. Hint: always put a SERTXD("Starting") at the top of your program.

Cheers, Alan.
 
Top