Conditioning Stepper Motor Clock Signal with a PLL ???

Beau Schwabe

Active Member
Anyone ever try this?

The clock source we are using to drive a servo controller has quite a bit of jitter due to the lack of deterministic timing in the micro producing the clock pulse.
I had a thought, but haven't had a chance to try it, that maybe if I used a PLL I could dramatically reduce the jitter allowing me to achieve higher RPMs on the Stepper.

Before I try this, I thought I might ask if anyone else has done this.

Thanks

rjenkinsgb

Well-Known Member
Off the top of my head:

If the PLL loop is damped to remove jitter, it will also limit the rate of speed change; try and ramp quickly and it may loose lock.

With little damping it could ramp quickly but not remove jitter so effectively.

If the application is such that position is critical, rather than just speed, I'd not risk adding anything in that could; lose track of counts. If it's speed only and a limited range, give it a go with a 4046 or similar.

Can't you get the suppliers of the pulse generating side to fix the problems in that?

dr pepper

Well-Known Member
Exactly what I have done a couple of times building a frequency standard, to remove modulation from a radio broadcast signal.
As mentioned though if you have a slow loop filter it will not remain synchronous.
Roman blacks website has an article for a dc motor controller with 'clockwork' accuracy, it counts pulses & if the motor cannot maintain torque at a particular moment it keeps track of the position in time & catches up later, you might be able to adapt the technique.
Can you microstep?, that gets the speed up.

Beau Schwabe

Active Member
Exact position is not important, and I am only interested in RPM here. I understand the need to ramp the speed so that motor sync will not be lost. The Jitter comes from using an arduino to read a pot and then supply a pulse stream to the stepper controller. The deterministic timing in this case is lost in the process of reading the pot value. I don't want to use a 555 or other jelly bean oscillator, because there are other things I want to apply. Sounds like I just need to program a PIC in Assembly with a fall through ADC approach to reading the POT so I can maintain deterministic timing.

"Can you microstep?, that gets the speed up. " ... I can and that does help with the Jitter, but in order for that to get the speed up, you need to have the processor overhead to produce a higher frequency to compensate for the higher resolution microstep. Pushing the processor speed limits as it is.

Nigel Goodwin

Super Moderator
"Can you microstep?, that gets the speed up. " ... I can and that does help with the Jitter, but in order for that to get the speed up, you need to have the processor overhead to produce a higher frequency to compensate for the higher resolution microstep. Pushing the processor speed limits as it is.
Presumably you're not 'pushing the limits' with the stepper pulsing?, as steppers don't go very fast anyway, and even micro-stepping to rotate the motor as fast as it will go shouldn't be straining a processor in any way. You mention a stepper controller, so there should be even less pressure on the processor.

Beau Schwabe

Active Member
Nigel,

The controller I have (DM2282 ) simply takes an input clock and direction to control a stepper. The micro stepping is hard wire programmable to 25,000 steps per revolution. Currently I have this set to 800 steps per revolution. The current is also hard wire programmable to 8.2A ... the stepper I am running (34HS38-4204D) is 4.2A and I have it programmed to 3.2A. (@4.2A the stepper gets very hot)

If the Stepper is going at a good clip and there is any lead or lag in the pulse stream, it can cause the stepper to run rough or cog severely limiting the top speed. If the pulse stream closely matches the phase inertia of the stepper, then a stepper can go much faster. From the perspective of the processor, reading a potentiometer causes any deterministic timing to go out the window.

Note: If I do use a 555 to supply pulses to the stepper controller I can spin the stepper almost 4 times faster than what I can get from the arduino with the potentiometer code. Using the arduino, you can hear the cogging from the stepper because the pulse stream is not steady and the stepper eventually looses sync.

Member
A jitter-free pulse stream from an Arduino should be possible at 8MHz, 4Mz, 2MHz etc.
How fast do you need?
Look here for more.

JimB

Super Moderator
Why not use a timer interupt to generate the clock pulse for the stepper?

The main program reads the pot and calculates the required values for the timer.
While all that is happening, the timer is running, times out and creates an interupt.

The interupt service routine:
pulses the stepper clock
reloads the new values for the timer
restarts the time
returns to main program

This should give a reasonably jitter free clock.

JimB

Beau Schwabe

Active Member
Thanks Wade and JimB .... I just discovered that. I am new to the arduino but have been programming PIC's for 30 years (old school in Assembly language)

Nigel Goodwin

Super Moderator
Nigel,

The controller I have (DM2282 ) simply takes an input clock and direction to control a stepper. The micro stepping is hard wire programmable to 25,000 steps per revolution. Currently I have this set to 800 steps per revolution. The current is also hard wire programmable to 8.2A ... the stepper I am running (34HS38-4204D) is 4.2A and I have it programmed to 3.2A. (@4.2A the stepper gets very hot)

If the Stepper is going at a good clip and there is any lead or lag in the pulse stream, it can cause the stepper to run rough or cog severely limiting the top speed. If the pulse stream closely matches the phase inertia of the stepper, then a stepper can go much faster. From the perspective of the processor, reading a potentiometer causes any deterministic timing to go out the window.

Note: If I do use a 555 to supply pulses to the stepper controller I can spin the stepper almost 4 times faster than what I can get from the arduino with the potentiometer code. Using the arduino, you can hear the cogging from the stepper because the pulse stream is not steady and the stepper eventually looses sync.
Post your code, I presume the problems are related to that - and as JimB suggested, using timer interrupts to generate the pulses would probably make life a lot simpler.

However, if you're using digitalWrite() to toggle your pin, this is a very slow instruction, and it's MUCH faster to use the native Atmel instruction rather than the Arduino one.

Beau Schwabe

Active Member
Here is the code, but I think I'm just going to program a PIC micro where I can use interrupts or an NCO to just set and forget the pulse duration and not have to worry about any overhead .... <-- something I am more familiar with. If someone wants to iron this out in arduino assembly code then more power to them. Im just not that familiar with the arduino platform yet. Ultimately I would want to just set a variable and have it run in the background.

The code below is better than what I was running, but still has cogging issues at higher speeds and isn't all that fast.

Code:
#include <AccelStepper.h>

// Define I/O pins
#define STEPPER_ENA_PIN  10     //YELLOW
#define STEPPER_DIR_PIN  11     //BLUE
#define STEPPER_STEP_PIN 12     //RED

// Define stepper and the pins
AccelStepper stepper(AccelStepper::DRIVER, STEPPER_STEP_PIN, STEPPER_DIR_PIN);

#define ANALOG_IN A0

void setup()
{
pinMode(STEPPER_ENA_PIN, OUTPUT);
digitalWrite(STEPPER_ENA_PIN, LOW);

stepper.setMaxSpeed(10000);
}

void loop()
{

stepper.setSpeed(analog_in*10);
stepper.runSpeed();
}

Nigel Goodwin

Super Moderator
How many steps per second are you trying to run?, the library itself says "Speeds of more than 1000 steps per second are unreliable."

It also uses multiple digitalWrite() instructions which are pretty slow as well.

dr pepper

Well-Known Member
First thing I'd try is not to update the value so often, maybe update it 5 or 10 times a second, using millis() instead of delay.
Also maybe find a low ovehead way of mathematical *10.
The above I htink might improve things, if your clever you'd maybe use a timer interrupt & get the update sync'd to minimise jitter.
I have used accel stepper, worked well for me, I used it with 3 pololu 32 microstep easydrivers, playig on the bench I got a motor (old) meant for 500rpm 1/2 step mode to whizz along at 3000rpm in 32 microstep mode, the 1.8v motor needed a supply of 24v to the board, but it worked for a few minutes without anything warming up.

Beau Schwabe

Active Member
To follow up on this I decided to use a PIC micro controller. The PIC reads a pot and drives an output pin from 0Hz to just over 31kHz.
With the Stepper controller configured for 200 pulses per revolution the Stepper tops out at about 20kHz or 6500 rpm
With the Stepper controller configured for 400 pulses per revolution the Stepper runs just fine at full throttle (31khz) at just over 4500 rpm

Here is the code below in case anyone is interested ... The cool thing is that this code does not use any interrupts and takes advantage of the NCO this particular micro has to offer.
Code:
;PIC 16F15313 - pinout

;VDD        1        8    VSS
;RA5        2        7    RA0/DAT
;RA4        3        6    RA1/CLK
;RA3/MCLR   4        5    RA2

;Connect Potentiometer wiper to RA5
;Connect Potentiometer outer legs to VDD and VSS

;RA2 output pin ranges from 0Hz to aproximately 31kHz as you turn the potentiometer

;Driving a stepper in 400 pulses per rev mode will turn the stepper at just over 4500 rpm

;  31kHz / 400 = 77.5 revolutions per second ... 77.5 x 60 = 4650 rpm

; Note: Switching the stepper controller to 200 pulses per rev, the stepper topped out at 20kHz before losing sync.
;
;  20kHz / 200 = 100 revolutions per second ... 100 x 60 = 6000 rpm

#include "p16lf15313.inc"

CONFIG1 = _FEXTOSC_OFF & _RSTOSC_HFINT32 & _CLKOUTEN_OFF & _CSWEN_ON & _FCMEN_ON
CONFIG2 = _MCLRE_OFF & _PWRTE_OFF & _LPBOREN_OFF & _BOREN_ON & _BORV_LO & _ZCD_OFF & _PPS1WAY_ON & _STVREN_ON
CONFIG3 = _WDTCPS_WDTCPS_31 & _WDTE_OFF & _WDTCWS_WDTCWS_7 & _WDTCCS_SC
CONFIG4 = _BBSIZE_BB512 & _BBEN_OFF & _SAFEN_OFF & _WRTAPP_OFF & _WRTB_OFF & _WRTC_OFF & _WRTSAF_OFF & _LVP_ON
CONFIG5 = _CP_ON

;*******************************************************************************
; Reset Vector
;*******************************************************************************

RES_VECT    CODE    0x0000          ; processor reset vector
GOTO    Initialize              ; go to beginning of program

;*******************************************************************************
; MAIN PROGRAM
;*******************************************************************************

MAIN_PROG CODE                      ; let linker place main program

Initialize:

banksel OSCCON1
movlw   b'00010000'
;         X....... Reserved
;          .XXX.... OSC Source
;         ....XXXX Divider
movwf   OSCCON1

banksel OSCFRQ
movlw   b'00000110'
;         XXXXX... Reserved
;         .....XXX HFINTOSC Frequency Selection
movwf   OSCFRQ

banksel TRISA
movlw   b'00100000'        ; Set RA5 as an INPUT
movwf   TRISA

banksel LATA        ; Set all OUTPUTS LOW
movlw   b'00000000'
movwf   LATA

banksel WDTCON1
movlw   b'01110000'
;         X....... Unemplemented
;         .XXX.... WDT Clock Select
;         ....X... Unemplemented
;         .....XXX WDT Window Select
movwf   WDTCON1

banksel RA2PPS    ; RA2->NCO1:NCO; Redirect NCO output to RA2
movlw   h'1A'
movwf   RA2PPS

banksel PMD1
movlw   b'00000000'
;          X....... NCO1MD: Disable Numerically Control Oscillator bit
;         .XXXX... Unimplemented: Read as ‘0’
;         .....X.. TMR2MD: Disable Timer TMR2 bit
;         ......X. TMR1MD: Disable Timer TMR1 bit
;         .......X TMR0MD: Disable Timer TMR0 bit
movwf   PMD1

banksel NCO1CON
movlw   b'10000000'
;          X....... N1EN: NCO1 Enable bit
;          .X...... Unimplemented: Read as ‘0’
;         ..X..... N1OUT: NCO1 Output bit
;         ...X.... N1POL: NCO1 Polarity bit
;         ....XXX. Unimplemented: Read as ‘0’
;          .......X N1PFM: NCO1 Pulse Frequency Mode bit
movwf   NCO1CON

banksel NCO1CLK
movlw   b'00000000'
;          XXX..... N1PWS<2:0>: NCO1 Output Pulse Width Selectbits(1)
;          ...X.... Unimplemented: Read as ‘0’
;         ....XXXX N1CKS<3:0>: NCO1 Clock Source Select bits

movwf   NCO1CLK

MOVLW   b'11110000'
;         ....XX..  Unimplemented: Read as ‘0’

banksel ANSELA
movlw   b'00100000'
;          XX......    Unimplemented
;         ..XX....  RA5 RA4 anaolg or digital select
;         ....X...  Unimplemented
;         .....XXX  RA2 RA1 RA0 anaolg or digital select
movwf   ANSELA

MOVLW   b'00010101'
;          XXXXXX..  CHS<5:0>: Analog Channel Select bits
;         ......X.  GO/DONE: ADC Conversion Status bit

banksel NCO1INCU
clrf    NCO1INCU

banksel NCO1INCH
clrf    NCO1INCH

banksel NCO1INCL
clrf    NCO1INCL

START:

btfsc    ADCON0,1    ; Is conversion done?
goto    CHECK_ADC   ; No, test again

banksel    NCO1INCH
movwf    NCO1INCH

banksel    NCO1INCL
movwf    NCO1INCL

GOTO START            ; loop forever

END

Last edited:

Nigel Goodwin

Super Moderator
The cool thing is that this code does not use any interrupts and takes advantage of the NCO this particular micro has to offer.
To be fair you're effectively using a hardware solution, which is the point of the NCO and other peripherals - no need to use assembler either, as the code is pretty irrelevent to the speed (and in any case C would be more than fast enough, even without the NCO).

Beau Schwabe

Active Member
Agreed about "no need to use assembler" .... but, I'm more old school. I program mostly in assembler anyway.

On a side note: Using a PLL I can take the stepper motor up to 8000 rpm in 200 steps per revolution mode. The Stepper motor controller claims it will take an input clock pulse up to 200kHz ... I was only driving it at about 27kHz

Last edited: