Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Conditioning Stepper Motor Clock Signal with a PLL ???

Status
Not open for further replies.

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
 
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?
 
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.
 
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.
 
"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.
 
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.
 
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
 
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,

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.
 
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);


// This defines the analog input pin for reading the control voltage
#define ANALOG_IN A0

void setup()
{ 
  pinMode(STEPPER_ENA_PIN, OUTPUT);
  digitalWrite(STEPPER_ENA_PIN, LOW);
 
  stepper.setMaxSpeed(10000);
}

void loop()
{
 
  // Read new speed
  int analog_in = analogRead(A0);
  stepper.setSpeed(analog_in*10);
  stepper.runSpeed();
}
 
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.
 
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.
 
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
  
    banksel ADCON1
    MOVLW   b'11110000'
    ;          X.......    ADFM: ADC Result Format Select bit
    ;         .XXX....  ADCS<2:0>: ADC Conversion Clock Select bits
    ;         ....XX..  Unimplemented: Read as ‘0’
    ;         ......XX  ADPREF<1:0>: ADC Positive Voltage Reference Configuration bits
    MOVWF   ADCON1
  
  
    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

  
    banksel ADCON0
    MOVLW   b'00010101'
    ;          XXXXXX..  CHS<5:0>: Analog Channel Select bits
    ;         ......X.  GO/DONE: ADC Conversion Status bit
    ;         .......X  ADON: ADC Enable bit
        MOVWF   ADCON0
  
    banksel NCO1INCU
    clrf    NCO1INCU
  
    banksel NCO1INCH
    clrf    NCO1INCH

    banksel NCO1INCL
    clrf    NCO1INCL
  
  
START:
    banksel    ADCON0
    bsf        ADCON0,1    ; Start conversion
  
CHECK_ADC: 
    btfsc    ADCON0,1    ; Is conversion done?
    goto    CHECK_ADC   ; No, test again
  
    banksel    ADRESH
    movf    ADRESH,W    ; Read upper 2 bits
    banksel    NCO1INCH
    movwf    NCO1INCH
  
    banksel    ADRESL
    movf    ADRESL,W    ; Read lower 8 bits
    banksel    NCO1INCL
    movwf    NCO1INCL


    GOTO START            ; loop forever

    END
 
Last edited:
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).
 
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:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top