Hello everyone,
I am currently using a Teensy 3.2 to control a stepper motor at relatively high speeds (1000 RPM max @ 800 steps / turn => around 13kHz).
I'm using a modified AccelStepper to control the motion, where the timing is not controlled by polling in the main loop but by using a timer. The AccelStepper computation takes place in the timer interrupt and takes around 20us to perform.
So far, everything is working fine but I would like to improve the motion smoothness by increasing the number of steps per turn (microstepping). Given the length of the interrupt it is not really possible to increase the step rate using the same code.
That's where I started to think about using DMA and a timer ; the general idea would be to compute a certain number of step delays at once, then rely on DMA to update the timer period.
2 DMA channels would be needed :
* the "main" channel that transfers data from a ring buffer to the timer register
* a second channel indicating the timer overflow, that triggers the main channel.
The delay buffer can be updated using interrupts from the main DMA channel (when the buffer is half and fully transferred).
There are still 2 issues that I have to figure out before starting experimenting :
* how can I handle the synchronization between the DMA and the main program at the end of a motion ? i.e. stop the timer and DMA transfer once the last step pulse has been sent. As I can see it, the best solution would be to change on the fly the number of remaining bytes for the DMA when filling the buffer for the last time, then wait for the "Done" interrupt. This looks like a race condition nightmare though
* i would really like to keep the real time behaviour of AccelStepper, about changing on the fly target point/speed/acceleration (I am currently using this feature to generate non-linear motion curves by changing regularly the speed/acceleration profile). For this to work, I would need to get the main DMA channel transfer count to know the exact position, and update the buffer while it's potentially being transferred (or maybe having a 2nd buffer ?).
I hope that my explanations are clear, please let me know if you have any suggestion or thought, especially regarding the last 2 points...
I will post an update when I start coding !
Cheers,
Tom
I am currently using a Teensy 3.2 to control a stepper motor at relatively high speeds (1000 RPM max @ 800 steps / turn => around 13kHz).
I'm using a modified AccelStepper to control the motion, where the timing is not controlled by polling in the main loop but by using a timer. The AccelStepper computation takes place in the timer interrupt and takes around 20us to perform.
So far, everything is working fine but I would like to improve the motion smoothness by increasing the number of steps per turn (microstepping). Given the length of the interrupt it is not really possible to increase the step rate using the same code.
That's where I started to think about using DMA and a timer ; the general idea would be to compute a certain number of step delays at once, then rely on DMA to update the timer period.
2 DMA channels would be needed :
* the "main" channel that transfers data from a ring buffer to the timer register
* a second channel indicating the timer overflow, that triggers the main channel.
The delay buffer can be updated using interrupts from the main DMA channel (when the buffer is half and fully transferred).
There are still 2 issues that I have to figure out before starting experimenting :
* how can I handle the synchronization between the DMA and the main program at the end of a motion ? i.e. stop the timer and DMA transfer once the last step pulse has been sent. As I can see it, the best solution would be to change on the fly the number of remaining bytes for the DMA when filling the buffer for the last time, then wait for the "Done" interrupt. This looks like a race condition nightmare though
* i would really like to keep the real time behaviour of AccelStepper, about changing on the fly target point/speed/acceleration (I am currently using this feature to generate non-linear motion curves by changing regularly the speed/acceleration profile). For this to work, I would need to get the main DMA channel transfer count to know the exact position, and update the buffer while it's potentially being transferred (or maybe having a 2nd buffer ?).
I hope that my explanations are clear, please let me know if you have any suggestion or thought, especially regarding the last 2 points...
I will post an update when I start coding !
Cheers,
Tom