Efficiently Pausing Execution

I have a routine which sends data out on a serial port in a loop. This is done within a loop and I have to set my mark space ratio and frequency by pausing execution in the loop. At the moment I am using the code below for my pauses which seems to be causing 100% (ish) processor usage.

Is there a more efficient way of pausing my loop execution which is accurate but is not going to hog the processor?

[code]Sub FeedWait(microseconds as integer)

dim old as double = microseconds

for i as integer = 1 to microseconds
App.YieldToNextThread

if microseconds-old >= microseconds then exit

next

return

End Sub[/code]

Have you tried Thread.Sleep or Application.SleepCurrentThread

Do you have more than one thread?

You could try sleeping instead of yielding.

dim millisec as double = floor(microseconds/1000)
if millisec> 0 then app.SleepCurrentThread(millisec)
while microseconds-old< microseconds
    app.YieldToNextThread
wend

[quote=247942:@Tim Hare]Do you have more than one thread?

You could try sleeping instead of yielding.

dim millisec as double = floor(microseconds/1000) if millisec> 0 then app.SleepCurrentThread(millisec) while microseconds-old< microseconds app.YieldToNextThread wend [/quote]

I need microsecond sleeps/pauses though. How can I achieve this?

Sleep takes a millisecond parameter, so do a gross first pass with sleep, followed by a short cpu intensive loop to get the precision you want. Or are you saying you never pause more than a millisecond. Can the serial port really respond that quickly?

The only efficient way to pause without a tight loop and with minimum processor usage is a timer. That said, regular Xojo timers are not in that range. I know TimerMBS has a much higher resolution of 1 ms https://forum.xojo.com/15748-monkeybread-software-releases-the-mbs-xojo-real-studio-plug-ins/0

In assembler way back when, there was that convenient instruction Nop in the z-80 assembler that did nothing for a processor cycle. Maybe a declare doing very little could achieve a similar result ?

I’ll expand on what I’m doing for clarity. The order/magnitude of things are for example, I am driving a stepper motor at a rate of 800 steps per second. To achieve 800 steps I need 1600 transitions as the steps are picked up on the rising edge of the square wave. 1600 transitions per second = 625 microseconds per transition. I set my mark space ratio (Duty Cycle) to approximately 20% so I need to set my bit high, sleep/wait/pause for 125 microseconds, set by bit low for 500 microseconds. The serial port transmit happens on every transition and i’m using 115k2 baud which should theoretically be up to 8.6 microsecond bit transitions.

I’m not sure that Xojo is a suitable solution for that problem space. Unless you’re driving the motor with a console type app. But even there…

That reminds me terribly much of the kind of things I used to do in assembler. Which would seem much better suited.

Those were also my days Michel.

That might be an option. Why do you say that, do you think I won’t achieve the timings I am after? I do seem to be having problems getting down to such small delays.

I guess I could run the serial driver side of things as a console app. Is it difficult to interact between a UI app and a console APP? Thing is I need to show progress in my UI app, at the moment I am doing this after each send to the serial port.

Michel, I completely agree but I like the challenge. This has been done extensively on the Arduino and Raspberry PI so should be possible on OSX. This is possible as it has been done by various developers, notably Mach3 for Windows. There is nothing for OSX although one developer claims to be the first in the world to have developed CNC controller for OSX so I have decided to make myself the second.

What I fear in OS X is that the system often preempts things and does a lot of stuff in the background, so your microsecond timing could be taken off beat. There must be ways to set higher priorities for apps, though. Probably means declares…

Good luck.

[quote=247977:@Michel Bujardet]What I fear in OS X is that the system often preempts things and does a lot of stuff in the background, so your microsecond timing could be taken off beat. There must be ways to set higher priorities for apps, though. Probably means declares…

Good luck.[/quote]
Well I am carrying this out in a thread so I could increase the priority of the thread. In fact I will try this now and see.

Thread priority and pragmas suspending any concurrent stuff is one thing within your app. What I am really concerned is system level maintenance, other apps running, background tasks and deamons, and all that paraphernalia that eats up cycles.

Its not too bad but needs fine tuning. I’m running at around 90 microsecond latency per step. This drops down to 20 microseconds when i’m not writing to the serial port but purely doing the step calculations. My serial port is running in the main thread so if I pull this out to run in its own thread I suspect I can do better than 90.

This in reality equates to approximately 3 second delay per minute when running at around 60,000 steps per minute. I can almost live with that but, I would like to improve it. But lets face it if you were running a CNC machining program which took an hour to machine a part and it took 1hr 3mins, It wouldn’t be the end of the world… In a non-production environment at least.

BTW this is all at 85% processor usage but you would expect the machine to be dedicated to CNC and all other apps/services not required would be shut down.

Oh and back to my OP, the most effective pausing of execution in this case worked out to be:

[code]Sub FeedWait(uSeconds as integer)
dim old as double = microseconds

do until old + uSeconds <= Microseconds

Loop

End Sub
[/code]

Only given that this is running it its own thread so it is not locking up the UI.

The accuracy of the above pause is within 3 or 4 micro seconds

[quote=247998:@Mike Charlesworth]Oh and back to my OP, the most effective pausing of execution in this case worked out to be:
The accuracy of the above pause is within 3 or 4 micro seconds[/quote]

That won’t work in general. Something as simple as the user clicking on a UI item would block that threads (threads are blocked within Event callbacks, for example.)

I think if you used this technique in a separate process (e.g. a command-line tool) it might be more robust.

[quote=248012:@Michael Diehr]That won’t work in general. Something as simple as the user clicking on a UI item would block that threads (threads are blocked within Event callbacks, for example.)

I think if you used this technique in a separate process (e.g. a command-line tool) it might be more robust.[/quote]

It does appear to be working. It is not increasing the latency when I click on the UI, drop a menu on the UI or open up a modal window. The only problem I do have is the serial port stutters because I have it running in the main thread at the moment but the stepping just continues to run in the background quite happily.

Those are some very impressive results, Mike. A stripped down, dedicated OS X box might just work. I know this won’t work on Windows. You routinely get pauses of up to 13 milliseconds at a time.

CNC controllers work in windows by using a language where one can access the output ports directly. There were many of these types using parallel ports. The “right” way to do this is to dedicate a microcontroller to control the cnc, and serve as the serial interface to the computer program.
I am not saying what is being attempted is not possible, but if it works it will be very dependent on the particular machine and what other programs are running at the same time. As a customer of a machine house, I would not be looking forward to sending them an order to be machined with such a system as I don’t think they could guarantee the yield.