Code to do 1/16th microstepping with a Propeller
pedward
Posts: 1,642
I tried to reply to the other post, but decided that this achievement deserves a new post, since I'm trying to contribute something useful and get feedback.
EDIT: Here's a video of a demo using this code: http://www.youtube.com/watch?v=yZqKV9s13Ho
I have successfully done 1/16th microstepping with a Propeller generating all of the phase commutation in 1 cog. The code uses the CTRA and CTRB to generate sine and cosine PWM waveforms that drive a half h-bridge chip. I haven't done any fancy current control, just the commutation sequences.
There were a couple of tricks in getting this to work, the worst was rounding error when dividing 360 / 64 = 5 on the propeller. I had to generate a table in a spreadsheet to get a proper degree table to generate the sine/cosine tables from. Once I had the degree table, the sine/cosine tables came out at 4pi just fine.
The other major issue was figuring out how to gate the pins, when I've got 4 outputs to drive and 2 counters to drive them. The solution was to detect the zero crossing and update the counter output pin depending upon what phase of the count I was in.
There is a curious issue with this driver, and I wanted some feedback from some of those amazingly, cryptically smart, people. The sine table is not weighted, so the motor accelerates and decelerates throughout the phase changes of the output. This is likely not desirable, as it indicates the steps are non-linear in length. I'd like to hear suggestions on how to improve this.
This code is presently running a stepper motor from an optical drive head assembly at 32,000 steps/s, sitting on my desk.
Without further ado, 1/16th PWM microstepping with the Propeller:
EDIT: Here's a video of a demo using this code: http://www.youtube.com/watch?v=yZqKV9s13Ho
I have successfully done 1/16th microstepping with a Propeller generating all of the phase commutation in 1 cog. The code uses the CTRA and CTRB to generate sine and cosine PWM waveforms that drive a half h-bridge chip. I haven't done any fancy current control, just the commutation sequences.
There were a couple of tricks in getting this to work, the worst was rounding error when dividing 360 / 64 = 5 on the propeller. I had to generate a table in a spreadsheet to get a proper degree table to generate the sine/cosine tables from. Once I had the degree table, the sine/cosine tables came out at 4pi just fine.
The other major issue was figuring out how to gate the pins, when I've got 4 outputs to drive and 2 counters to drive them. The solution was to detect the zero crossing and update the counter output pin depending upon what phase of the count I was in.
There is a curious issue with this driver, and I wanted some feedback from some of those amazingly, cryptically smart, people. The sine table is not weighted, so the motor accelerates and decelerates throughout the phase changes of the output. This is likely not desirable, as it indicates the steps are non-linear in length. I'd like to hear suggestions on how to improve this.
This code is presently running a stepper motor from an optical drive head assembly at 32,000 steps/s, sitting on my desk.
Without further ado, 1/16th PWM microstepping with the Propeller:
[FONT=courier new]{{ Demonstration of PWM microstepping with the Propeller To use this code, connect the pins as such: COS -- CTRB -- 0 -- PHSA SIN -- CTRA -- 1 -- /PHSA COS -- /CTRB -- 2 -- PHSB SIN -- /CTRA -- 3 -- /PHSB }} CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 microsteps = 64 VAR long parameter long cs[microsteps],sn[microsteps] word ca,sa PUB go | x repeat x from 0 to microsteps-1 cs[x] := cos(deg[x],256) sn[x] := sin(deg[x],256) cognew(@entry, @parameter) repeat repeat x from 0 to microsteps-1 '15 deg steps ca:=cs[x] sa:=sn[x] parameter := ca << 16 + sa 'pack cosine and sine waitcnt(2500 + cnt) 'wait a little while before next update PUB sin(degree, range) : s | c,z,angle angle := (degree*91)~>2 ' *22.75 c := angle & $800 z := angle & $1000 if c angle := -angle angle |= $E000>>1 angle <<= 1 s := word[angle] if z s := -s return (s*range)~>16 ' return sin = -range..+range PUB cos(degree,range) return sin(degree+90,range) DAT 'assembly cog which updates the PWM cycle on APIN 'for audio PWM, fundamental freq which must be out of auditory range (period < 50?S) org entry mov dira, diraval 'set APIN to output mov ctra, ctraval1 'establish counter A mode and APIN mov ctrb, ctrbval1 'establish counter A mode and APIN mov frqa, #1 'set counter to increment 1 each cycle mov frqb, #1 'set counter to increment 1 each cycle mov time, cnt 'record current time add time, period 'establish next period :loop rdlong value, par 'get an up to date pulse width mov a, value shl a, #16 'unpack a shr a, #16 'unpack a mov b, value shr b, #16 'unpack b cmp a, #$1FF wc 'test for 16bit signed value if_nc or a, mask 'sign extend cmp b, #$1FF wc 'test for 16bit signed value if_nc or b, mask 'sign extend cmps a, #0 wc 'wave change muxnc outa, #16 'status display if_c movs ctra, #2 'out pin 2 if_c neg a, a 'flip sign if_nc movs ctra, #0 'out pin 0 cmps b, #0 wc 'wave change muxnc outa, #32 'status display if_c movs ctrb, #3 'out pin 3 if_c neg b, b 'flip sign if_nc movs ctrb, #1 'out pin 1 neg phsa, a 'back up phsa neg phsb, b 'back up phsb waitcnt time, period 'wait until next period jmp #:loop 'loop for next cycle diraval long 1111 'APIN=0 ctraval1 long 100 << 26 + 0 'NCO/PWM APIN=0 ctrbval1 long 100 << 26 + 1 'NCO/PWM APIN=0 ctraval2 long 100 << 26 + 2 'NCO/PWM APIN=0 ctrbval2 long 100 << 26 + 3 'NCO/PWM APIN=0 period long 255 '800kHz (1.25?S period) (_clkfreq / period) mask long $FFFF0000 time res 1 value res 1 a res 1 b res 1 deg long 0,5,11,17,22,28,34,40,45,51,57,62,68,74,80,85,91,97,102,108,114,120,125,131,137,142,148,154,160,165,171,177,182,188,194,200,205,211,217,222,228,234,240,245,251,257,262,268,274,280,285,291,297,302,308,314,320,325,331,337,342,348,354,360 [/FONT]
Comments
I had to build a drive to generate a high current sine wave for a linear (Voice-coil) driver. The PWM output from the prop comes out nice, but due to the on/off times of my power transistors, I got almost no drive current until the very peak of the cycle, somewhere around 80-85 % duty cycle. I finally got a usable wave by doing a custom output, watching my wave-shape and fine-tuning the duty cycle for about 15 steps of up and down, but never got a nice, clean high current sine wave. The attached photo shows about the best I got. The sine wave on the left was the pressure output and the sine wave on the right a corresponding expansion of a mock artery.
This was "Close enough" for my prototype, but I'd love to know if anyone else out there has a reasonably easy circuit for generating a smooth, high current ( 2-6 amp ) sine wave with the Prop. The filtered PWM into a linear driver works fine, but the expense of the drive itself cancels out a lot of the cost benefit of using the propeller for inexpensive motion controllers.
I thought about experimenting with the HB-25, but needed a bit more than 12 volts for this. A high power stepper motor drive would be too expensive doing it this way anyway. Anyone got a cheap circuit for high voltage, high current output?
K.B.