On each step one winding goes high or one winding goes low, snaking around the 5 phases.
I'd recommend first tackling this as it will prove the rest of the hardware and is much easier to
get working in the first instance.
sinusoidal PWM involves synchonizing 5 PWM clocks and providing duty cycles of the form
50% + amplitude% * sin (phase)
The synchronization is required with a 5-wire motor as the windings cannot be independently
driven. The amplitude controls the strength of drive (there is no equivalent to this with trapezoidal
drive method).
Note that is amplitude is zero, all the PWM channels are at 50% duty cycle and exactly in phase.
The windings see no drive at all in this condition.
So on every PWM cycle you need to provide a new sin(phase) value to each PWM cog that are 72 degrees
apart. A DDS loop can dole out the values, using a sine lookup table (alas the ROM table is probably too slow
to use for 5 waveforms, a complete 360 degree table that's a power-of-two in size in RAM is the way
to go.
Scaling by the amplitude involves a multiply - that's best farmed out to the PWM cogs to share the
workload.
BTW in case its not obvious 5 phase PWM control is analogous to 3 phase control, you just replace 3 by 5 and 120 degree by 72 degree, so any 3-phase code can be adapted.
and there is also this useful chestnut
"This results in the 2-phase having 200 steps per rotation, 1.8° per step, while the 5-phase has 500 steps per rotation, 0.72° per step. The increased resolution of the 5-phase is inherent to its design. When coupled with a microstepping driver, the 5-phase motor can make steps as small as 0.00288°, however, position accuracy and repeatability are still subject to the motor's mechanical accuracy. The mechanical accuracy of both the 2-phase and 5-phase motor is ± 3 arc minutes (0.05°)."
that Mechanical limit, is Step/14.4, which explains why Microsteps above 32 are not really mentioned.
It does mean the 256 steps mentioned is outside the scope of these motors, but PhPi's nifty code can manage higher PWM kHz for reduced steps.
50% + amplitude% * sin (phase)
.........................................
A DDS loop can dole out the values, using a sine lookup table (alas the ROM table is probably too slow
to use for 5 waveforms, a complete 360 degree table that's a power-of-two in size in RAM is the way
to go.
Scaling by the amplitude involves a multiply - that's best farmed out to the PWM cogs to share the
workload.
"Sine wave" in the thread title got my attention because I have wondered what it would take to design a variable frequency drive for a three phase induction motor for a possible future project. This looks like good information. I get the sense that I'm going to have to learn about "DDS loops".
It is possible to use two single DDS devices that operate on the same master clock to output two signals whose phase relationship can then be directly controlled. In Figure 8, two AD9834s are programmed using one reference clock, with the same reset pin being used to update both parts. Using this setup, it is possible to do I-Q modulation.
Figure 8
Figure 8. Multiple DDS ICs in synchronous mode.
A reset must be asserted after power-up and prior to transferring any data to the DDS. This sets the DDS output to a known phase, which serves as the common reference point that allows synchronization of multiple DDS devices. When new data is sent simultaneously to multiple DDS units, a coherent phase relationship can be maintained, and their relative phase offset can be predictably shifted by means of the phase-offset register.
FWIW, here's a program that outputs analog sine waves 72° apart:
CON_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000CLK_PIN = 6PH0_PIN = 1PH1_PIN = 2PH2_PIN = 3PH3_PIN = 4PH4_PIN = 5NO_PIN = $ff
PUB start
cognew(@wavegen, @group0)
cognew(@wavegen, @group1)
cognew(@wavegen, @group2)
waitcnt(cnt + clkfreq / 10)
dira[CLK_PIN]~~
frqa := $10000000ctra := %00100 << 26 | CLK_PIN
repeatDATgroup0 long CLK_PIN << 24 | PH0_PIN << 16 | PH1_PIN << 8 | 0group1 long CLK_PIN << 24 | PH2_PIN << 16 | PH3_PIN << 8 | 100group2 long CLK_PIN << 24 | PH4_PIN << 16 | NO_PIN << 8 | 200org0wavegen rdlong phase0,par
mov clkpin,phase0shr clkpin,#24mov clkmask,#1shl clkmask,clkpin
mov ph0pin,phase0shr ph0pin,#16and ph0pin,#$ff
mov ph1pin,phase0shr ph1pin,#8and ph1pin,#$ff
and phase0,#$ff
add phase0,#sine
mov phase1,phase0add phase1,#50cmp ph0pin,#NO_PIN wz
if_nz movs ctr0,ph0pin
if_nz mov ctra,ctr0if_nz mov acc,#1if_nz shl acc,ph0pin
if_nz mov dira,acc
cmp ph1pin,#NO_PIN wz
if_nz movs ctr0,ph1pin
if_nz mov ctrb,ctr0if_nz mov acc,#1if_nz shl acc,ph1pin
if_nz or dira,acc
main_lp movs loadfrqa,phase0movs loadfrqb,phase1add phase0,#1cmp phase0,#sine+250 wz
if_z mov phase0,#sine
add phase1,#1cmp phase1,#sine+250 wz
if_z mov phase1,#sine
waitpne clkmask,clkmask
waitpeq clkmask,clkmask
loadfrqa mov frqa,0-0loadfrqb mov frqb,0-0jmp #main_lp
ctr0 long %00110 << 26sine long $7fffffff,$83377685,$866e67e4,$89a44f0c,$8cd8a718long $900aeb61,$933a9798,$966727da,$999018c3,$9cb4e786long $9fd51201,$a2f016d2,$a605756b,$a914ae2b,$ac1d426b
long $af1eb49b,$b2188850,$b50a425b,$b7f368dd,$bad38358long $bdaa1ac6,$c076b9ab,$c338ec28,$c5f0400b,$c89c44e7long $cb3c8c21,$cdd0a905,$d05830d6,$d2d2bae1,$d53fe08b
long $d79f3d64,$d9f06f39,$dc33161d,$de66d480,$e08b4f3b
long $e2a02d9e,$e4a5197f,$e699bf49,$e87dce08,$ea50f778long $ec12f00d,$edc36f07,$ef622e77,$f0eeeb4c,$f2696561long $f3d15f81,$f5269f79,$f668ee1c,$f798174a,$f8b3ea00long $f9bc3858,$fab0d796,$fb91a02d,$fc5e6dc3,$fd171f3b
long $fdbb96b7,$fe4bb9a1,$fec770a8,$ff2ea7ce,$ff814e5f
long $ffbf5701,$ffe8b7aa,$fffd69ab,$fffd69aa,$ffe8b7a7long $ffbf56fb,$ff814e57,$ff2ea7c2,$fec7709b,$fe4bb990long $fdbb96a5,$fd171f26,$fc5e6dab,$fb91a013,$fab0d77a
long $f9bc3839,$f8b3e9de,$f7981726,$f668edf6,$f5269f51long $f3d15f57,$f2696534,$f0eeeb1d,$ef622e46,$edc36ed4long $ec12efd8,$ea50f740,$e87dcdcf,$e699bf0d,$e4a51941long $e2a02d5e,$e08b4efa,$de66d43d,$dc3315d8,$d9f06ef2long $d79f3d1c,$d53fe040,$d2d2ba95,$d0583088,$cdd0a8b5long $cb3c8bd0,$c89c4495,$c5f03fb8,$c338ebd3,$c076b955long $bdaa1a6f,$bad382ff,$b7f36883,$b50a4201,$b21887f5long $af1eb43f,$ac1d420e,$a914adcc,$a605750c,$a2f01672long $9fd511a0,$9cb4e725,$99901861,$96672777,$933a9735long $900aeafe,$8cd8a6b4,$89a44ea9,$866e6781,$83377621long $7fffff9b,$7cc88916,$799197b6,$765bb08e,$73275883long $6ff5143b,$6cc56804,$6998d7c2,$666fe6da,$634b1817long $602aed9d,$5d0fe8cd,$59fa8a34,$56eb5175,$53e2bd35long $50e14b06,$4de77752,$4af5bd48,$480c96c8,$452c7c4e
long $4255e4e0,$3f8945fc,$3cc71381,$3a0fbf9f,$3763bac5long $34c3738d,$322f56aa,$2fa7cedb,$2d2d44d2,$2ac01f29long $2860c251,$260f907e,$23cce99c,$21992b3b,$1f74b082long $1d5fd221,$1b5ae641,$19664079,$178231bc,$15af084f
long $13ed0fbb,$123c90c3,$109dd156,$0f111483,$0d969a71long $0c2ea052,$0ad9605c,$099711bd,$0867e891,$074c15dd
long $0643c787,$054f284b,$046e5fb7,$03a19224,$02e8e0ae
long $02446934,$01b4464d,$01388f48,$00d15825,$007eb196long $0040a8f7,$00174850,$00029652,$00029656,$0017485b
long $0040a909,$007eb1b0,$00d15847,$01388f71,$01b4467e
long $0244696c,$02e8e0ee,$03a1926a,$046e6005,$054f28a1long $0643c7e4,$074c1641,$0867e8fb,$0997122e,$0ad960d5long $0c2ea0d2,$0d969af7,$0f111510,$109dd1e9,$123c915d
long $13ed105c,$15af08f5,$17823269,$1966412c,$1b5ae6fa
long $1d5fd2df,$1f74b146,$21992c05,$23ccea6b,$260f9153long $2860c32b,$2ac02008,$2d2d45b5,$2fa7cfc3,$322f5798long $34c3747f,$3763bbbb,$3a0fc09a,$3cc71480,$3f8946ff
long $4255e5e6,$452c7d57,$480c97d4,$4af5be58,$4de77865long $50e14c1c,$53e2be4e,$56eb5290,$59fa8b51,$5d0fe9ec
long $602aeebe,$634b193b,$666fe7ff,$6998d8e9,$6cc5692b
long $6ff51563,$732759ad,$765bb1b8,$799198e1,$7cc88a40clkpin res 1clkmask res 1ph0pin res 1acc res 1ph1pin res 1phase0 res 1phase1 res 1
It uses three PASM cogs and their counters to produce five DUTY-mode outputs. Phase advancements are synchronized to an NCO clock output on P0. I filtered the outputs with an RC filter (1K, 220pF) to produce the following scope trace. (My scope has only four channels, so I couldn't show the fifth channel. But I did verify that it was there and correct.)
The unfiltered DUTY-mode output changes state way too fast to input to a PWM-style driver. But there are chips that convert analog voltages to a proper PWM signal. Alternatively, one could produce a sawtooth output on another pin and use that with comparators to produce the PWM'd signals.
The unfiltered DUTY-mode output changes state way to fast to input to a PWM-style driver. But there are chips that convert analog voltages to a proper PWM signal. Alternatively, one could produce a sawtooth output on another pin and use that with comparators to produce the PWM'd signals.
There are also Class-D audio amplifiers and the TI ones spec around 70KHz of power bandwidth, so they might conveniently drive sine voltages into motors.
Way back when.... When I was choosing steppers and drivers, I clearly saw that Oriental Motors was going in a proprietary direction.... So I ran the other way, and instead I chose the norm. I would hate to be in your shoes.
EDIT: Sell those motors and buy normal stepper motors, and you will be glad you did. Just my two cents.
There are also Class-D audio amplifiers and the TI ones spec around 70KHz of power bandwidth, so they might conveniently drive sine voltages into motors.
But not a 5-wire 5-phase motor surely, as the windings are not independent.
There are also Class-D audio amplifiers and the TI ones spec around 70KHz of power bandwidth, so they might conveniently drive sine voltages into motors.
But not a 5-wire 5-phase motor surely, as the windings are not independent.
Well, yes, clearly not from a single channel of Class-D
Sell those motors and buy normal stepper motors, and you will be glad you did. Just my two cents.
Despite the five-phase motors being more complicated to interface and program, I believe they do have an advantage when it comes to smooth running. Mercedes Benz recognized such an advantage when they came out with their 300D (a five-cylinder diesel) many years ago.
"Depending on your particular application, a 2-phase motor may suffice. However, 5-phase stepper motors offer higher resolution, lower vibration, higher acceleration and deceleration rates (due to smaller step angles), and are less likely to lose synchronization due to overshooting/undershooting than a 2-phase stepper motor. For applications requiring high precision, low noise and low vibration, 5-phase is the better technology."
... "Depending on your particular application, a 2-phase motor may suffice. However, 5-phase stepper motors offer higher resolution, lower vibration, higher acceleration and deceleration rates (due to smaller step angles), and are less likely to lose synchronization due to overshooting/undershooting than a 2-phase stepper motor. For applications requiring high precision, low noise and low vibration, 5-phase is the better technology."
All of that is true, until you bring micro-stepping to the table.
Of course, they rather skirt around that, with statements like this
"Vibration
Because of the smaller step angles in 5-phase stepper motors, 0.72° versus 1.8° in a 2-phase motor, the vibration in a 5-phase motor is much less than in a 2-phase."
And nothing was said in the article about resonance. Two-phase steppers can have terrible resonance characteristics (cogging and losing steps), unless they are physically damped and/or employ clever programming to minimize time spent in the resonance zone. (Maybe even dithering would work here?) I once had to incorporate a spring-loaded cork-and-metal drag mechanism (as in a fishing reel) to dampen out resonance in a stepper drive.
I do not know how five-phase motors' resonance characteristics compare.
And nothing was said in the article about resonance. Two-phase steppers can have terrible resonance characteristics (cogging and losing steps), unless they are physically damped and/or employ clever programming to minimize time spent in the resonance zone. (Maybe even dithering would work here?) I once had to incorporate a spring-loaded cork-and-metal drag mechanism (as in a fishing reel) to dampen out resonance in a stepper drive.
I do not know how five-phase motors' resonance characteristics compare.
I had to look up to see what "cogging" was.
In one of my stepper projects I dealt with the cogging problem by reducing the PWM duty cycle whenever the stepper was rotating slowly or during acceleration/deceleration. I inserted a PNP transistor into the power supply. (Low side NPN did not work.)
Question - why can't you just use 5 cogs and time it out to get the frequency you need?
Of course, that is possible.
Phil's code could have used one timer per COG, rather than the 2 timers each COGs already has, and consumed 5 COGs instead.
Despite the five-phase motors being more complicated to interface and program, I believe they do have an advantage when it comes to smooth running.
Perhaps this is true, but there are always pros and cons to every trade off. To me, simplicity, and readily available, inexpensive parts, are worth there weight in gold. As I have told you before, the best advice you ever gave me, was to purchase some of the readily available PWM stepper drivers. Prior to purchasing those drivers, I was going in circles and wasting a lot of time and money.
Perhaps this is true, but there are always pros and cons to every trade off. To me, simplicity, and readily available, inexpensive parts, are worth there weight in gold. As I have told you before, the best advice you ever gave me, was to purchase some of the readily available PWM stepper drivers. Prior to purchasing those drivers, I was going in circles and wasting a lot of time and money.
Absolutely agree: Phil Pilgrim's advice is worth its weight in gold.
I have a question.
In the code below, If "i" (is from 0 to 7), why in "duty" is it only shifted left 6 times not 7?
Thank you
________________________________________________________________________________________
From PWMx8.Demo.spin
PUB start | i, duty
' Program to demonstrate the pwm_x8 object.
pwm.start(base_pin, %1111_1111, 23000) 'Setup for PWM output on pins A16 - A23 at 23KHz.
repeat
repeat value from 0 to 511
repeat i from 0 to 7
duty := ((value + (i << 6)) & 511)
if duty > 255
duty := 511 - duty
pwm.duty(base_pin + i, duties[duty])
______________________________________________________________________________________________
I have been reading thru code/manuals/forum posts and application notes and I am crossed eyed now.
I am getting there but need a little help.
Code below. Questions in red.
Thank You
________________________________________________________________________________________________
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
CLK_PIN = 6
PH0_PIN = 1
PH1_PIN = 2---Pin assignments with base 10? Should be binary right?
PH2_PIN = 3
PH3_PIN = 4
PH4_PIN = 5
NO_PIN = $ff
PUB start
cognew(@wavegen, @group0)
cognew(@wavegen, @group1)
cognew(@wavegen, @group2)
waitcnt(cnt + clkfreq / 10)
dira[CLK_PIN]~~
frqa := $10000000
ctra := %00100 << 26 | CLK_PIN----Is this OR'ng 26 and clk_pin
repeat or binary number shifted left 26 times then OR'ed with a base 10 number?
DAT
group0 long CLK_PIN << 24 | PH0_PIN << 16 | PH1_PIN << 8 | 0
group1 long CLK_PIN << 24 | PH2_PIN << 16 | PH3_PIN << 8 | 100---What it this?
group2 long CLK_PIN << 24 | PH4_PIN << 16 | NO_PIN << 8 | 200---What is going on here?
org 0
wavegen rdlong phase0,par
mov clkpin,phase0
shr clkpin,#24--\
mov clkmask,#1----\Why shr/mov/shl when it was done above?
shl clkmask,clkpin--/
mov ph0pin,phase0
shr ph0pin,#16
and ph0pin,#$ff
mov ph1pin,phase0
shr ph1pin,#8
and ph1pin,#$ff
and phase0,#$ff
add phase0,#sine
mov phase1,phase0
add phase1,#50
shift binds more tightly than or, its generating bit fields by oring them together, and individual fields
by shifting them left. Basically most of this code is packing several fields into one long.
The thing with sine is a table in cog ram, whose first entry has the label sine. The code is traversing
phase0 & phase1 from sine to sine+250, ie phaseX are register numbers (used by the MOVS instructions
to modify the instructions that set FRQA and FRQB)
Comments
Right, that requires all the outputs to be in step, basically one DDS generated signal controls all the pins.
As background the standard trapezoidal step pattern is something like:
1 00111110000011111000 2 00001111100000111110 3 10000011111000001111 4 11100000111110000011 5 11111000001111100000
On each step one winding goes high or one winding goes low, snaking around the 5 phases.I'd recommend first tackling this as it will prove the rest of the hardware and is much easier to
get working in the first instance.
sinusoidal PWM involves synchonizing 5 PWM clocks and providing duty cycles of the form
50% + amplitude% * sin (phase)
The synchronization is required with a 5-wire motor as the windings cannot be independently
driven. The amplitude controls the strength of drive (there is no equivalent to this with trapezoidal
drive method).
Note that is amplitude is zero, all the PWM channels are at 50% duty cycle and exactly in phase.
The windings see no drive at all in this condition.
So on every PWM cycle you need to provide a new sin(phase) value to each PWM cog that are 72 degrees
apart. A DDS loop can dole out the values, using a sine lookup table (alas the ROM table is probably too slow
to use for 5 waveforms, a complete 360 degree table that's a power-of-two in size in RAM is the way
to go.
Scaling by the amplitude involves a multiply - that's best farmed out to the PWM cogs to share the
workload.
The Oriental Motor docs have a slight variant on that, with a 3-on-7 off step mapping, which looks to always have 3 driving.
Step 0 1 2 3 4 5 6 7 8 9 VOHGA H H L L L L L L L H VOHGB L H H H L L L L L L VOHGC L L L H H H L L L L VOHGD L L L L L H H H L L VOHGE L L L L L L L H H H VOLA L L L L H H H L L L VOLB L L L L L L H H H L VOLC H L L L L L L L H H VOLD H H H L L L L L L L VOLE L L H H H L L L L L An “H” represents that the respective MOSFET is active.
and there is also this useful chestnut
"This results in the 2-phase having 200 steps per rotation, 1.8° per step, while the 5-phase has 500 steps per rotation, 0.72° per step. The increased resolution of the 5-phase is inherent to its design. When coupled with a microstepping driver, the 5-phase motor can make steps as small as 0.00288°, however, position accuracy and repeatability are still subject to the motor's mechanical accuracy. The mechanical accuracy of both the 2-phase and 5-phase motor is ± 3 arc minutes (0.05°)."
that Mechanical limit, is Step/14.4, which explains why Microsteps above 32 are not really mentioned.
It does mean the 256 steps mentioned is outside the scope of these motors, but PhPi's nifty code can manage higher PWM kHz for reduced steps.
https://www.analog.com/en/analog-dialogue/articles/all-about-direct-digital-synthesis.html
It is possible to use two single DDS devices that operate on the same master clock to output two signals whose phase relationship can then be directly controlled. In Figure 8, two AD9834s are programmed using one reference clock, with the same reset pin being used to update both parts. Using this setup, it is possible to do I-Q modulation.
Figure 8
Figure 8. Multiple DDS ICs in synchronous mode.
A reset must be asserted after power-up and prior to transferring any data to the DDS. This sets the DDS output to a known phase, which serves as the common reference point that allows synchronization of multiple DDS devices. When new data is sent simultaneously to multiple DDS units, a coherent phase relationship can be maintained, and their relative phase offset can be predictably shifted by means of the phase-offset register.
loop waitcnt time, #delay add phase, frequency ' phase increment mov ph0, phase mov ph1, phase mov ph2, phase mov ph3, phase mov ph4, phase add ph1, H33333333 ' 5 equally spaced phases add ph2, H66666666 add ph3, H9999999a add ph4, Hcccccccd shr ph0, #24 ' take high bits to index lookup table... shr ph1, #24 shr ph2, #24 shr ph3, #24 shr ph4, #24 .... jmp #loop
Just a phase variable in binary radians and lockstep timing. Use the phase as you like each timeCON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 CLK_PIN = 6 PH0_PIN = 1 PH1_PIN = 2 PH2_PIN = 3 PH3_PIN = 4 PH4_PIN = 5 NO_PIN = $ff PUB start cognew(@wavegen, @group0) cognew(@wavegen, @group1) cognew(@wavegen, @group2) waitcnt(cnt + clkfreq / 10) dira[CLK_PIN]~~ frqa := $10000000 ctra := %00100 << 26 | CLK_PIN repeat DAT group0 long CLK_PIN << 24 | PH0_PIN << 16 | PH1_PIN << 8 | 0 group1 long CLK_PIN << 24 | PH2_PIN << 16 | PH3_PIN << 8 | 100 group2 long CLK_PIN << 24 | PH4_PIN << 16 | NO_PIN << 8 | 200 org 0 wavegen rdlong phase0,par mov clkpin,phase0 shr clkpin,#24 mov clkmask,#1 shl clkmask,clkpin mov ph0pin,phase0 shr ph0pin,#16 and ph0pin,#$ff mov ph1pin,phase0 shr ph1pin,#8 and ph1pin,#$ff and phase0,#$ff add phase0,#sine mov phase1,phase0 add phase1,#50 cmp ph0pin,#NO_PIN wz if_nz movs ctr0,ph0pin if_nz mov ctra,ctr0 if_nz mov acc,#1 if_nz shl acc,ph0pin if_nz mov dira,acc cmp ph1pin,#NO_PIN wz if_nz movs ctr0,ph1pin if_nz mov ctrb,ctr0 if_nz mov acc,#1 if_nz shl acc,ph1pin if_nz or dira,acc main_lp movs loadfrqa,phase0 movs loadfrqb,phase1 add phase0,#1 cmp phase0,#sine+250 wz if_z mov phase0,#sine add phase1,#1 cmp phase1,#sine+250 wz if_z mov phase1,#sine waitpne clkmask,clkmask waitpeq clkmask,clkmask loadfrqa mov frqa,0-0 loadfrqb mov frqb,0-0 jmp #main_lp ctr0 long %00110 << 26 sine long $7fffffff,$83377685,$866e67e4,$89a44f0c,$8cd8a718 long $900aeb61,$933a9798,$966727da,$999018c3,$9cb4e786 long $9fd51201,$a2f016d2,$a605756b,$a914ae2b,$ac1d426b long $af1eb49b,$b2188850,$b50a425b,$b7f368dd,$bad38358 long $bdaa1ac6,$c076b9ab,$c338ec28,$c5f0400b,$c89c44e7 long $cb3c8c21,$cdd0a905,$d05830d6,$d2d2bae1,$d53fe08b long $d79f3d64,$d9f06f39,$dc33161d,$de66d480,$e08b4f3b long $e2a02d9e,$e4a5197f,$e699bf49,$e87dce08,$ea50f778 long $ec12f00d,$edc36f07,$ef622e77,$f0eeeb4c,$f2696561 long $f3d15f81,$f5269f79,$f668ee1c,$f798174a,$f8b3ea00 long $f9bc3858,$fab0d796,$fb91a02d,$fc5e6dc3,$fd171f3b long $fdbb96b7,$fe4bb9a1,$fec770a8,$ff2ea7ce,$ff814e5f long $ffbf5701,$ffe8b7aa,$fffd69ab,$fffd69aa,$ffe8b7a7 long $ffbf56fb,$ff814e57,$ff2ea7c2,$fec7709b,$fe4bb990 long $fdbb96a5,$fd171f26,$fc5e6dab,$fb91a013,$fab0d77a long $f9bc3839,$f8b3e9de,$f7981726,$f668edf6,$f5269f51 long $f3d15f57,$f2696534,$f0eeeb1d,$ef622e46,$edc36ed4 long $ec12efd8,$ea50f740,$e87dcdcf,$e699bf0d,$e4a51941 long $e2a02d5e,$e08b4efa,$de66d43d,$dc3315d8,$d9f06ef2 long $d79f3d1c,$d53fe040,$d2d2ba95,$d0583088,$cdd0a8b5 long $cb3c8bd0,$c89c4495,$c5f03fb8,$c338ebd3,$c076b955 long $bdaa1a6f,$bad382ff,$b7f36883,$b50a4201,$b21887f5 long $af1eb43f,$ac1d420e,$a914adcc,$a605750c,$a2f01672 long $9fd511a0,$9cb4e725,$99901861,$96672777,$933a9735 long $900aeafe,$8cd8a6b4,$89a44ea9,$866e6781,$83377621 long $7fffff9b,$7cc88916,$799197b6,$765bb08e,$73275883 long $6ff5143b,$6cc56804,$6998d7c2,$666fe6da,$634b1817 long $602aed9d,$5d0fe8cd,$59fa8a34,$56eb5175,$53e2bd35 long $50e14b06,$4de77752,$4af5bd48,$480c96c8,$452c7c4e long $4255e4e0,$3f8945fc,$3cc71381,$3a0fbf9f,$3763bac5 long $34c3738d,$322f56aa,$2fa7cedb,$2d2d44d2,$2ac01f29 long $2860c251,$260f907e,$23cce99c,$21992b3b,$1f74b082 long $1d5fd221,$1b5ae641,$19664079,$178231bc,$15af084f long $13ed0fbb,$123c90c3,$109dd156,$0f111483,$0d969a71 long $0c2ea052,$0ad9605c,$099711bd,$0867e891,$074c15dd long $0643c787,$054f284b,$046e5fb7,$03a19224,$02e8e0ae long $02446934,$01b4464d,$01388f48,$00d15825,$007eb196 long $0040a8f7,$00174850,$00029652,$00029656,$0017485b long $0040a909,$007eb1b0,$00d15847,$01388f71,$01b4467e long $0244696c,$02e8e0ee,$03a1926a,$046e6005,$054f28a1 long $0643c7e4,$074c1641,$0867e8fb,$0997122e,$0ad960d5 long $0c2ea0d2,$0d969af7,$0f111510,$109dd1e9,$123c915d long $13ed105c,$15af08f5,$17823269,$1966412c,$1b5ae6fa long $1d5fd2df,$1f74b146,$21992c05,$23ccea6b,$260f9153 long $2860c32b,$2ac02008,$2d2d45b5,$2fa7cfc3,$322f5798 long $34c3747f,$3763bbbb,$3a0fc09a,$3cc71480,$3f8946ff long $4255e5e6,$452c7d57,$480c97d4,$4af5be58,$4de77865 long $50e14c1c,$53e2be4e,$56eb5290,$59fa8b51,$5d0fe9ec long $602aeebe,$634b193b,$666fe7ff,$6998d8e9,$6cc5692b long $6ff51563,$732759ad,$765bb1b8,$799198e1,$7cc88a40 clkpin res 1 clkmask res 1 ph0pin res 1 acc res 1 ph1pin res 1 phase0 res 1 phase1 res 1
It uses three PASM cogs and their counters to produce five DUTY-mode outputs. Phase advancements are synchronized to an NCO clock output on P0. I filtered the outputs with an RC filter (1K, 220pF) to produce the following scope trace. (My scope has only four channels, so I couldn't show the fifth channel. But I did verify that it was there and correct.)The unfiltered DUTY-mode output changes state way too fast to input to a PWM-style driver. But there are chips that convert analog voltages to a proper PWM signal. Alternatively, one could produce a sawtooth output on another pin and use that with comparators to produce the PWM'd signals.
-Phil
Very nifty.
There are also Class-D audio amplifiers and the TI ones spec around 70KHz of power bandwidth, so they might conveniently drive sine voltages into motors.
use strict; foreach my $i (0 .. 249) { if ($i == 0) { print "sine long " } elsif ($i % 5 == 0) { print " long " } printf "\$%8.8x", int((sin($i * 6.2831854 / 250) * 0.5 + 0.5) * 0xffffffff); print $i % 5 == 4 ? "\n" : "," }
-Phil
EDIT: Sell those motors and buy normal stepper motors, and you will be glad you did. Just my two cents.
Well, yes, clearly not from a single channel of Class-D
From this article:
"Depending on your particular application, a 2-phase motor may suffice. However, 5-phase stepper motors offer higher resolution, lower vibration, higher acceleration and deceleration rates (due to smaller step angles), and are less likely to lose synchronization due to overshooting/undershooting than a 2-phase stepper motor. For applications requiring high precision, low noise and low vibration, 5-phase is the better technology."
-Phil
All of that is true, until you bring micro-stepping to the table.
Of course, they rather skirt around that, with statements like this
"Vibration
Because of the smaller step angles in 5-phase stepper motors, 0.72° versus 1.8° in a 2-phase motor, the vibration in a 5-phase motor is much less than in a 2-phase."
I do not know how five-phase motors' resonance characteristics compare.
-Phil
Resonance also improves with microstepping. Some nice plots here : https://www.trinamic.com/technology/std-technologies/microstepping/
In one of my stepper projects I dealt with the cogging problem by reducing the PWM duty cycle whenever the stepper was rotating slowly or during acceleration/deceleration. I inserted a PNP transistor into the power supply. (Low side NPN did not work.)
Of course, that is possible.
Phil's code could have used one timer per COG, rather than the 2 timers each COGs already has, and consumed 5 COGs instead.
Perhaps this is true, but there are always pros and cons to every trade off. To me, simplicity, and readily available, inexpensive parts, are worth there weight in gold. As I have told you before, the best advice you ever gave me, was to purchase some of the readily available PWM stepper drivers. Prior to purchasing those drivers, I was going in circles and wasting a lot of time and money.
I have a question.
In the code below, If "i" (is from 0 to 7), why in "duty" is it only shifted left 6 times not 7?
Thank you
________________________________________________________________________________________
From PWMx8.Demo.spin
PUB start | i, duty
' Program to demonstrate the pwm_x8 object.
pwm.start(base_pin, %1111_1111, 23000) 'Setup for PWM output on pins A16 - A23 at 23KHz.
repeat
repeat value from 0 to 511
repeat i from 0 to 7
duty := ((value + (i << 6)) & 511)
if duty > 255
duty := 511 - duty
pwm.duty(base_pin + i, duties[duty])
______________________________________________________________________________________________
I am getting there but need a little help.
Code below. Questions in red.
Thank You
________________________________________________________________________________________________
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
CLK_PIN = 6
PH0_PIN = 1
PH1_PIN = 2---Pin assignments with base 10? Should be binary right?
PH2_PIN = 3
PH3_PIN = 4
PH4_PIN = 5
NO_PIN = $ff
PUB start
cognew(@wavegen, @group0)
cognew(@wavegen, @group1)
cognew(@wavegen, @group2)
waitcnt(cnt + clkfreq / 10)
dira[CLK_PIN]~~
frqa := $10000000
ctra := %00100 << 26 | CLK_PIN----Is this OR'ng 26 and clk_pin
repeat or binary number shifted left 26 times then OR'ed
with a base 10 number?
DAT
group0 long CLK_PIN << 24 | PH0_PIN << 16 | PH1_PIN << 8 | 0
group1 long CLK_PIN << 24 | PH2_PIN << 16 | PH3_PIN << 8 | 100---What it this?
group2 long CLK_PIN << 24 | PH4_PIN << 16 | NO_PIN << 8 | 200---What is going on here?
org 0
wavegen rdlong phase0,par
mov clkpin,phase0
shr clkpin,#24--\
mov clkmask,#1----\Why shr/mov/shl when it was done above?
shl clkmask,clkpin--/
mov ph0pin,phase0
shr ph0pin,#16
and ph0pin,#$ff
mov ph1pin,phase0
shr ph1pin,#8
and ph1pin,#$ff
and phase0,#$ff
add phase0,#sine
mov phase1,phase0
add phase1,#50
cmp ph0pin,#NO_PIN wz
if_nz movs ctr0,ph0pin
if_nz mov ctra,ctr0
if_nz mov acc,#1
if_nz shl acc,ph0pin
if_nz mov dira,acc
cmp ph1pin,#NO_PIN wz
if_nz movs ctr0,ph1pin
if_nz mov ctrb,ctr0
if_nz mov acc,#1
if_nz shl acc,ph1pin
if_nz or dira,acc
main_lp movs loadfrqa,phase0
movs loadfrqb,phase1
add phase0,#1
cmp phase0,#sine+250 wz---Why add 250 to sine?
if_z mov phase0,#sine
add phase1,#1
cmp phase1,#sine+250 wz
if_z mov phase1,#sine
waitpne clkmask,clkmask
waitpeq clkmask,clkmask
loadfrqa mov frqa,0-0
loadfrqb mov frqb,0-0
jmp #main_lp
________________________________________________________________________________________________
-Phil
by shifting them left. Basically most of this code is packing several fields into one long.
The thing with sine is a table in cog ram, whose first entry has the label sine. The code is traversing
phase0 & phase1 from sine to sine+250, ie phaseX are register numbers (used by the MOVS instructions
to modify the instructions that set FRQA and FRQB)