Some time ago I built an application to run on my Raspberry Pi 3. Among other things, it controlled a stepper motor using a stepper motor driver board. To make the motor move one "step", I had to set an output pin High and Low. The change in voltage would cause the motor to move into its next position. I needed to have a small time delay between the voltage changes for it to work properly.
My initial research showed that the best-practice way to get a time delay in a UWP app was to use the asynchronous Task.Delay() method. I didn't have access to my Thread.Sleep method in UWP, so I gave it a try. Also, since the method takes an integer as a parameter, 1 millisecond was the shortest delay I could use.
Here's an example of my first attempt, making 1600 successive "steps":
for (int i = 0; i < 1600; i++)
{
// (stepper driver board makes one step for every low-to-high transition)
StepperStepPin.Write(GpioPinValue.Low);
await Task.Delay(1); // wait 1 ms
StepperStepPin.Write(GpioPinValue.High);
await Task.Delay(1); // wait 1 ms
}
In theory, with 2ms delay in each iteration of the loop, this should have taken about 3.2 seconds. In reality, it ended up taking about 51 seconds. As best as I can tell, the act of calling this asynchronous delay method adds about 15 ms of overhead to start up the asynchronous thread. If I were using longer delays only once in awhile this wouldn't be noticeable. But when I have to do it hundreds or thousands of times, it adds up quickly.
After lots more digging, I found a solution that worked for me. I ditched the async method and went with a synchronous approach using the System.Diagnostics.Stopwatch class, and it also lets me have sub-millisecond delays:
private readonly Stopwatch _sw = new System.Diagnostics.Stopwatch();
private void ShortDelay(double milliseconds) {
_sw.Start();
while ((_sw.Elapsed).TotalMilliseconds < milliseconds) { }
_sw.Reset();
}
//////////////////////////////////////////
for (int i = 0; i < 1600; i++)
{
// (stepper driver board makes one step for every low-to-high transition)
StepperStepPin.Write(GpioPinValue.Low);
ShortDelay(0.5); // wait 0.5 ms
StepperStepPin.Write(GpioPinValue.High);
ShortDelay(0.5); // wait 0.5 ms
}
I would assume the little while loop could cause problems with a UI thread, but my app is headless, so it didn't really affect my particular application. But it still feels like a bit of a hack, like there should be a better solution here to get a reasonably accurate millisecond-or-less time delay.
I admit I feel like I don't fully understand async/await, and I'd like to know if there's a more appropriate solution here. So if you have some expertise here and can explain a better way, or can explain why this method is acceptable, any feedback would be appreciated.
Thanks.