Perhaps the best solution is to use an interrupt-driven stepper driver using one of the hardware timers. That way, step pulses are created "in the background" by the hardware. This not only provides much more consistent step pulse timing, but also frees up the foreground code to do many other things "at the same time".