;******
************************************************************************
;
; LiniStepper v2
; PIC 16F84 / 16F628 / 16F628A code (updated 628A June 2007)
; Copyright Aug 2002 - Nov 2009 - Roman Black www.romanblack.com
;
; PIC assembler code for the LiniStepper stepper motor driver board.
; 200/400/1200/3600 steps
;
; v2.0 New version 2.0; 2nd Nov 2009.
; * modified v1 source to work with new Lini v2 PCB.
; * STEP and DIR are the same, but POWER is now "ENABLE" (active LOW)
; (so the POWER pin function is inverted in Lini v2)
; v2.1 Updated 16th Nov 2010.
; Now incorporates update suggested by Brian D Freeman; improves
; performance by skipping the current calculation on the hi-lo
; transition of the step input.
;
; (set mplab TABS to 5 for best viewing this .asm file)
;******************************************************************************
;==============================================================================
; mplab settings
ERRORLEVEL -224 ; suppress annoying message because of option/tris
ERRORLEVEL -302 ; suppress message because of bank select in setup ports
LIST b=5, n=97, t=ON, st=OFF ;
; absolute listing tabs=5, lines=97, trim long lines=ON, symbol table=OFF
;==============================================================================
; processor defined
;include
;include
include
; processor config
IFDEF __16F84A
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC
ENDIF
IFDEF __16F628
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _BODEN_OFF & _LVP_OFF
ENDIF
IFDEF __16F628A
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _BODEN_OFF & _LVP_OFF
ENDIF
;==============================================================================
; Variables here
;-------------------------------------------------
IFDEF __16F84A
#define RAM_START 0x0C
#define RAM_END RAM_START+d'68' ; 16F84 has only 68 ram
ENDIF
IFDEF __16F628
#define RAM_START 0x20
#define RAM_END RAM_START+d'96' ; F628 has 96 ram
ENDIF
IFDEF __16F628A
#define RAM_START 0x20
#define RAM_END RAM_START+d'96' ; F628A has 96 ram
ENDIF
;-------------------------------------------------
CBLOCK RAM_START
status_temp ; used for int servicing
w_temp ; used for int servicing
step ; (0-71) ustep position!
steptemp ; for calcs
phase ; stores the 4 motor phase pins 0000xxxx
current1 ; for current tween pwm
current2 ; for current tween pwm
inputs ; stores new input pins
inputs_last ; stores last states of input pins
ENDC
;-------------------------------------------------
; PIC input pins for porta
#define STEP 0 ; / = move 1 step, \=do nothing
#define DIR 1 ; lo= cw, hi=ccw
#define POWER 2 ; lo=full power, hi=half power
; (Note! POWER pin was inverted for v2 !!!)
;-------------------------------------------------
; Custom instructions!
#define skpwne skpnz ; after subxx, uses zero
#define skpweq skpz ; after subxx, uses zero
#define skpwle skpc ; after subxx, uses carry
#define skpwgt skpnc ; after subxx, uses carry
;==============================================================================
; CODE GOES HERE
org 0x0000 ; Set program memory base at reset vector 0x00
reset
goto main ;
;==============================================================================
; INTERRUPT vector here
org 0x0004 ; interrupt routine must start here
int_routine
;-------------------------------------------------
; first we preserve w and status register
movwf w_temp ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf status_temp ; save off contents of STATUS register
;-------------------------------------------------
; we get here every 256 timer0 ticks 3900Hz
; int body code here if you want
;-------------------------------------------------
; finally we restore w and status registers and
; clear TMRO int flag now we are finished.
int_exit
bcf INTCON,T0IF ; reset the tmr0 interrupt flag
movf status_temp,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp,f
swapf w_temp,w ; restore pre-isr W register contents
retfie ; return from interrupt
;-------------------------------------------------
;==============================================================================
;******************************************************************************
; MOVE MOTOR sets 8 portb output pins to control motor
;******************************************************************************
; NOTE!! var step is used for sequencing the 0-71 steps
; uses tables! so keep it first in the code and set PCLATH to page 0
;------------------
move_motor ; goto label
;------------------
;-------------------------------------------------
; this code controls the phase sequencing and current
; settings for the motor.
; there are always 72 steps (0-71)
; we can split the main table into 2 halves, each have identical
; current sequencing. That is only 12 entries for hardware current.
; Then can x3 the table to get 36 table entries which cover all 72 steps.
; the 36 entries jump to 36 code pieces, which set the current values
; for the 2 possible tween steps... We need 2 current values, one
; for the x2 value and one for the x1 value.
;-------------------------------------------------
; PHASE SEQUENCING (switch the 4 coils)
; there are 4 possible combinations for the phase switching:
; each have 18 steps, total 72 steps:
; A+ B+ range 0 step 0-17
; A- B+ range 1 18-35
; A- B- range 2 36-53
; A+ B- range 3 54-71
;-------------------------------------------------
; find which of the 4 ranges we are in
movf step,w ; get step
movwf steptemp ; store as working temp
movf steptemp,w ;
sublw d'35' ; sub to test
skpwle ;
goto half_hi ; wgt, steptemp is 36-71 (upper half)
;-------------------------
half_low ; wle, steptemp is 0-35
movf steptemp,w ;
sublw d'17' ; sub to test
skpwle ;
goto range1 ; wgt
range0 ; wle
movlw b'00000101' ; 0101 = A+ B+
goto phase_done ;
range1
movlw b'00001001' ; 1001 = A- B+
goto phase_done ;
;-------------------------
half_hi ; steptemp is 36-71
; NOTE! must subtract 36 from steptemp, so it
; will become 0-35 and ok with table later!
movlw d'36' ; subtract 36 from steptemp,
subwf steptemp,f ; (now steptemp is 0-35)
; now find the range
movf steptemp,w ;
sublw d'17' ; sub to test
skpwle ;
goto range3 ; wgt
range2 ; wle
movlw b'00001010' ; 1010 = A- B-
goto phase_done ;
range3
movlw b'00000110' ; 0110 = A+ B-
phase_done ; note! steptemp is always 0-35 by here
movwf phase ; store phase values
;-------------------------------------------------
; at this point we have the phasing done and stored as the last
; 4 bits in var phase; 0000xxxx
; now we have 36 possible current combinations, which we can do
; by separate code fragments, from a jump table.
; as we have 2 power modes; full and low power, we
; need 2 tables.
;-------------------------------------------------
btfsc inputs,POWER ; select table to use
goto table_lowpower ;
;-------------------------------------------------
; HIGH POWER TABLE
;-------------------------------------------------
table_highpower ;
movf steptemp,w ; add steptemp to the PCL
addwf PCL,f ;
; here are the 36 possible values;
;-------------------------
goto st00 ; * (hardware 6th steps)
goto st01 ; (pwm tween steps)
goto st02 ; (pwm tween steps)
goto st03 ; *
goto st04 ;
goto st05 ;
goto st06 ; *
goto st07 ;
goto st08 ;
goto st09 ; *
goto st10 ;
goto st11 ;
goto st12 ; *
goto st13 ;
goto st14 ;
goto st15 ; *
goto st16 ;
goto st17 ;
goto st18 ; *
goto st19 ;
goto st20 ;
goto st21 ; *
goto st22 ;
goto st23 ;
goto st24 ; *
goto st25 ;
goto st26 ;
goto st27 ; *
goto st28 ;
goto st29 ;
goto st30 ; *
goto st31 ;
goto st32 ;
goto st33 ; *
goto st34 ;
goto st35 ;
;-------------------------------------------------
; LOW POWER TABLE
;-------------------------------------------------
; as low power mode is for wait periods we don't need to
; maintain the full step precision and can wait on the
; half-step (400 steps/rev). This means much easier code tables.
; The nature of the board electronics is not really suited
; for LOW power microstepping, but it could be programmed here
; if needed.
; NOTE!! uses my hi-torque half stepping, not normal half step.
; doing half stepping with the 55,25 current values gives;
; 55+25 = 80
; max current 100+100 = 200
; typical (high) current 100+50 = 150
; so low power is about 1/2 the current of high power mode,
; giving about 1/4 the motor heating and half the driver heating.
; for now it uses only half-steps or 8 separate current modes.
; we only have to use 4 actual current modes as
; the table is doubled like the table_highpower is.
; NOTE!! I have left the table full sized so it can be modified
; to 1200 or 3600 steps if needed.
;-------------------------------------------------
table_lowpower ;
movf steptemp,w ; add steptemp to the PCL
addwf PCL,f ;
; here are the 36 possible values;
;-------------------------
; A+ B+ (A- B-)
goto lp00 ;
goto lp00 ;
goto lp00 ;
goto lp00 ;
goto lp00 ; 55,25 (100,45) current low (high)
goto lp00 ;
goto lp00 ;
goto lp00 ;
goto lp00 ;
goto lp09 ;
goto lp09 ;
goto lp09 ;
goto lp09 ;
goto lp09 ; 25,55 (45,100)
goto lp09 ;
goto lp09 ;
goto lp09 ;
goto lp09 ;
;-------------------------
; A- B+ (A+ B-)
goto lp18 ;
goto lp18 ;
goto lp18 ;
goto lp18 ;
goto lp18 ; 25,55 (45,100)
goto lp18 ;
goto lp18 ;
goto lp18 ;
goto lp18 ;
goto lp27 ;
goto lp27 ;
goto lp27 ;
goto lp27 ;
goto lp27 ; 55,25 (100,45)
goto lp27 ;
goto lp27 ;
goto lp27 ;
goto lp27 ;
;-------------------------------------------------
; all tables done, no more tables after this point!
;-------------------------------------------------
; next are the 36 code fragments for the high power table.
; CURRENT INFO.
; hardware requires that we send the entire 8 bits to the motor
; at one time, to keep pwm fast.
; ----xxxx, where xxxx is the coils on/off phasing (done)
; xxxx----, where xxxx is the current settings for the A and B phases;
; xx------, where xx is current for A phase
; --xx----, where xx is current for B phase
; hardware currents for 6th stepping have 4 possible values;
; 00 = 0% current
; 01 = 25% current
; 10 = 55% current
; 11 = 100% current
;-------------------------------------------------
; PWM INFO.
; hardware gives us 6th steps, or 1200 steps/rev.
; to get 3600 steps/rev we need TWO more
; "tween" steps between every proper hardware 6th step.
; to do this we set 2 currents, current1 and current2.
; then we do FAST pwm, with 2 time units at current2,
; and 1 time unit at current1.
; this gives a current which is between the two currents,
; proportionally closer to current2. (2/3 obviously)
; this gives the ability to get 2 evenly spaced "tween" currents
; between our hardware 6th step currents, and go from 1200 to 3600.
; the next 36 code fragments set the 2 currents desired, then
; we goto a fast-pwm loop (same loop used for all currents)
; which modulates between the 2 currents and gives final
; output current.
;-------------------------------------------------
st00 ; (6th step)
movf phase,w ; get coil phasing (is 0000xxxx)
iorlw b'11000000' ; set currents; 100,0
movwf current2 ;
movwf current1 ;
goto pwm ;
st01 ; (tween step)
movf phase,w ; get coil phasing
iorlw b'11000000' ; set 100,0
movwf current2 ;
movf phase,w ;
iorlw b'11010000' ; set 100,25
movwf current1 ;
goto pwm ;
st02 ; (tween step)
movf phase,w ; get coil phasing
iorlw b'11010000' ; set 100,25
movwf current2 ;
movf phase,w ;
iorlw b'11000000' ; set 100,0
movwf current1 ;
goto pwm ;
;-------------------------
st03 ; (6th step)
movf phase,w ;
iorlw b'11010000' ; set 100,25
movwf current2 ;
movwf current1 ;
goto pwm ;
st04 ;
movf phase,w ;
iorlw b'11010000' ; set 100,25
movwf current2 ;
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current1 ;
goto pwm ;
st05 ;
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current2 ;
movf phase,w ;
iorlw b'11010000' ; set 100,25
movwf current1 ;
goto pwm ;
;-------------------------
st06 ; (6th step)
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current2 ;
movwf current1 ;
goto pwm ;
st07 ;
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current2 ;
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current1 ;
goto pwm ;
st08 ;
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current2 ;
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current1 ;
goto pwm ;
;-------------------------
st09 ; (6th step)
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current2 ;
movwf current1 ;
goto pwm ;
st10 ;
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current2 ;
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current1 ;
goto pwm ;
st11 ;
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current2 ;
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current1 ;
goto pwm ;
;-------------------------
st12 ; (6th step)
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current2 ;
movwf current1 ;
goto pwm ;
st13 ;
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current2 ;
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current1 ;
goto pwm ;
st14 ;
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current2 ;
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current1 ;
goto pwm ;
;-------------------------
st15 ; (6th step)
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current2 ;
movwf current1 ;
goto pwm ;
st16 ;
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current2 ;
movf phase,w ;
iorlw b'00110000' ; set 0,100
movwf current1 ;
goto pwm ;
st17 ;
movf phase,w ;
iorlw b'00110000' ; set 0,100
movwf current2 ;
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current1 ;
goto pwm ;
;-------------------------
;-------------------------
st18 ; (6th step)
movf phase,w ;
iorlw b'00110000' ; set 0,100
movwf current2 ;
movwf current1 ;
goto pwm ;
st19 ;
movf phase,w ;
iorlw b'00110000' ; set 0,100
movwf current2 ;
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current1 ;
goto pwm ;
st20 ;
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current2 ;
movf phase,w ;
iorlw b'00110000' ; set 0,100
movwf current1 ;
goto pwm ;
;-------------------------
st21 ; (6th step)
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current2 ;
movwf current1 ;
goto pwm ;
st22 ;
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current2 ;
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current1 ;
goto pwm ;
st23 ;
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current2 ;
movf phase,w ;
iorlw b'01110000' ; set 25,100
movwf current1 ;
goto pwm ;
;-------------------------
st24 ; (6th step)
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current2 ;
movwf current1 ;
goto pwm ;
st25 ;
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current2 ;
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current1 ;
goto pwm ;
st26 ;
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current2 ;
movf phase,w ;
iorlw b'10110000' ; set 55,100
movwf current1 ;
goto pwm ;
;-------------------------
st27 ; (6th step)
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current2 ;
movwf current1 ;
goto pwm ;
st28 ;
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current2 ;
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current1 ;
goto pwm ;
st29 ;
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current2 ;
movf phase,w ;
iorlw b'11110000' ; set 100,100
movwf current1 ;
goto pwm ;
;-------------------------
st30 ; (6th step)
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current2 ;
movwf current1 ;
goto pwm ;
st31 ;
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current2 ;
movf phase,w ;
iorlw b'11010000' ; set 100,25
movwf current1 ;
goto pwm ;
st32 ;
movf phase,w ;
iorlw b'11010000' ; set 100,25
movwf current2 ;
movf phase,w ;
iorlw b'11100000' ; set 100,55
movwf current1 ;
goto pwm ;
;-------------------------
st33 ; (6th step)
movf phase,w ;
iorlw b'11010000' ; set 100,25
movwf current2 ;
movwf current1 ;
goto pwm ;
st34 ;
movf phase,w ;
iorlw b'11010000' ; set 100,25
movwf current2 ;
movf phase,w ;
iorlw b'11000000' ; set 100,0
movwf current1 ;
goto pwm ;
st35 ;
movf phase,w ;
iorlw b'11000000' ; set 100,0
movwf current2 ;
movf phase,w ;
iorlw b'11010000' ; set 100,25
movwf current1 ;
goto pwm ;
; high power table done!
;-------------------------------------------------
; next are the 4 code fragments for the low power table.
; (no PWM is used)
;-------------------------------------------------
lp00 ;
movf phase,w ;
iorlw b'10010000' ; set 55,25
movwf current2 ;
movwf current1 ;
goto pwm ;
lp09 ;
movf phase,w ;
iorlw b'01100000' ; set 25,55
movwf current2 ;
movwf current1 ;
goto pwm ;
lp18 ;
movf phase,w ;
iorlw b'01100000' ; set 25,55
movwf current2 ;
movwf current1 ;
goto pwm ;
lp27 ;
movf phase,w ;
iorlw b'10010000' ; set 55,25
movwf current2 ;
movwf current1 ;
goto pwm ;
;-------------------------------------------------
;------------------------------------------------------------------------------
;******************************************************************************
; Main
;******************************************************************************
;
;------------------
main ; goto label
;------------------
;---------------------------------------------
; do initial setup for ports and ints and stuff
call setup ; this is our only proper call...
; it is called only once, and does not really need
; to be a function.
;---------------------------------------------
; main operating loop is here.
;---------------------------------------------
goto move_motor ; will set the motor to step 0,
; and loop permanently from there
;---------------------------------------------
goto main ; safe loop, should never get here anyway.
;==============================================================================
;******************************************************************************
; NEW INPUTS input change was detected
;******************************************************************************
;
;------------------
new_inputs ; goto tag
;------------------
;-------------------------------------------------
; when we enter here:
; * one or more PORTA inputs have just changed
; * inputs_last contains last PORTA inputs values
; * inputs contains new PORTA inputs values
;-------------------------------------------------
; must first detect which input pins changed.
; ---x---- RA4 * mode bit1 ( 00=200 step 01=400 step
; ----x--- RA3 * mode bit0 10=1200 step 11=3600 step )
; -----x-- RA2 * power (Lini v2; now 0 = full power!)
; ------x- RA1 * direction
; -------x RA0 * step
; if step went hi, we move the step (step++ or step--)
; if step went low, ignore
; ignore change in direction pin
; ignore change in power pin
; ignore change in mode pins
; (all pins besides step are handled automatically in move_motor)
;-------------------------------------------------
movf inputs,w ; xor to compare new inputs with last values
xorwf inputs_last,f ; now inputs_last has the diff.
btfss inputs_last,STEP ; test if step input changed
goto ni_end ;
; step input changed!
btfsc inputs,STEP ; test if change was lo-hi or hi-lo
goto trans_hi ; lo-hi, so process a step!
; hi-lo, so ignore this transition
bcf inputs_last,STEP ; record new state of step pin
goto pwm ; fast exit back to pwm()
;-------------------------------------------------
; step input changed lo-hi!
; now must make a step forward or back, based
; on the state of the dir pin.
; here it gets complex as we have 4 operating modes,
; determined by the state of the 2 input pins RA4 and RA3;
; ---00--- 200 steps
; ---01--- 400 steps
; ---10--- 1200 steps
; ---11--- 3600 steps
; there are 4 separate code systems to handle stepping
; in the 4 modes;
;-------------------------------------------------
trans_hi
; find which of the 4 modes we are in
btfss inputs,4 ; test hi bit
goto mode_lo ;
mode_hi ; must be 1200 or 3600
btfss inputs,3 ; test lo bit
goto mode_1200 ;
;-------------------------------------------------
mode_3600 ; 3600 mode (72/1)
; each step is 1
btfss inputs,DIR ; test direction input
goto m36_up ;
m36_down
decf step,f ; step--
btfss step,7 ; test for roll under <0
goto ni_end ; ok
; rolled under!
movlw d'71' ; force to top step (72-1)
movwf step ;
goto ni_end ;
m36_up
incf step,f ; step++
movf step,w ; test for roll over >71
sublw d'71' ; sub to test
skpwle ;
clrf step ; wgt, rolled over so force to step 0
goto ni_end ;
;-------------------------------------------------
mode_1200 ; 1200 mode (72/3)
; each step is mod 3 (0,3,6,9,12 - 66, 69 etc)
btfss inputs,DIR ; test direction input
goto m12_up ;
m12_down
movlw d'3' ; amount to subtract
subwf step,f ; step-=3
btfss step,7 ; test for roll under <0
goto ni_end ; ok
; rolled under!
movlw d'69' ; force to top step (72-3)
movwf step ;
goto ni_end ;
m12_up
movlw d'3' ; amount to add
addwf step,f ; step+=3
;
movf step,w ; test for roll over >69
sublw d'69' ; sub to test
skpwle ;
clrf step ; wgt, rolled over so force to step 0
goto ni_end ;
;-------------------------------------------------
mode_lo ; must be 200 or 400
btfss inputs,3 ; test lo bit
goto mode_200 ;
;-------------------------------------------------
mode_400 ; 400 mode (72/9)
; note! we do special half stepping here.
; there are ONLY 8 valid steps:
; 4, 13, 22, 31, 40, 49, 58, 67
; these steps give 100,45 and 35,100 combos, good
; enough for now. (should average 100,41)
btfss inputs,DIR ; test direction input
goto m4_up ;
m4_down
movlw d'9' ; amount to subtract
subwf step,f ; step-=9
btfss step,7 ; test for roll under <0
goto ni_end ; ok
; rolled under!
movlw d'67' ; force to top (full) step
movwf step ;
goto ni_end ;
m4_up
movlw d'9' ; amount to add
addwf step,f ; step+=9
;
movf step,w ; test for roll over
sublw d'67' ; sub to test
skpwgt ;
goto ni_end ; wle, is ok
movlw d'4' ; wgt, rolled over so force to bottom step 5
movwf step ;
goto ni_end ;
;-------------------------------------------------
mode_200 ; 200 mode (72/18)
; NOTE!! this has special needs as we can't use
; step 0, we need to stay on the "2 steps on" steps.
; there are ONLY 4 valid steps; 9, 27, 45, 63
btfss inputs,DIR ; test direction input
goto m2_up ;
m2_down
movlw d'18' ; amount to subtract
subwf step,f ; step-=18
btfss step,7 ; test for roll under <0
goto ni_end ; ok
; rolled under!
movlw d'63' ; force to top (full) step (72-(18/2))
movwf step ;
goto ni_end ;
m2_up
movlw d'18' ; amount to add
addwf step,f ; step+=18
;
movf step,w ; test for roll over
sublw d'63' ; sub to test
skpwgt ;
goto ni_end ; wle, is ok
movlw d'9' ; wgt, rolled over so force to bottom step 9
movwf step ;
goto ni_end ;
;-------------------------------------------------
ni_end
movf inputs,w ; save a copy of the inputs
movwf inputs_last ;
goto move_motor ; go and make it all happen
;------------------------------------------------------------------------------
;******************************************************************************
; PWM is the fast pwm loop
;******************************************************************************
; NOTE!! we enter the code in the middle of the loop!
;-------------------------------------------------
; the 2 target currents were set in the move_motor code.
; what this function does is spend 2 time units at current2,
; and 1 time unit at current1.
; actual is 8 clocks at current2
; and 4 clocks at current 1
; total 12 cycles, so 333 kHz with 16MHz resonator.
; this gives an average pwm current of 2/3 the way between
; current2 and current1.
; the routine is kept short to keep pwm frequency high, so it
; is easy to smooth in hardware by the ramping caps.
; IMPORTANT! is timed by clock cycles, don't change this code!
; it also checks for any change in input pins here
; the 8/4 code seen here was supplied by Eric Bohlman (thanks!)
;-------------------------------------------------
pwm_loop
; first output current1 to motor
movf current1,w ; get currents and phase switching
movwf PORTB ; send to motor!
nop ; timing delay
nop ;
; (4 cycles)
;-------------------------
pwm ; main entry!
; better to enter at current2 for motor power.
; now output current2
movf current2,w ;
movwf PORTB ; send to motor!
nop ; safe wait 250nS
; now test input pins
movf PORTA,w ; get pin values from port
xorwf inputs_last,w ; xor to compare new inputs with last values
skpnz
goto pwm_loop ; z, inputs not changed, so keep looping
; (8 cycles)
;-------------------------------------------------
; nz, one or more input pins have changed!
xorwf inputs_last,w ; restore xored value back to the orig inputs value
movwf inputs ;
goto new_inputs ;
;-------------------------------------------------
;------------------------------------------------------------------------------
;******************************************************************************
; SETUP sets port directions and interrupt stuff etc,
;******************************************************************************
; NOTE!! is the only proper funtion, is done before other activity
;------------------
setup ; routine tag
;------------------
;-------------------------------------------------
; Note! there are added bits for the 16F628!
; here we set up peripherals and port directions.
; this will need to be changed for different PICs.
;-------------------------------------------------
; OPTION setup
movlw b'10000010' ;
; x------- ; 7, 0=enable, 1=disable, portb pullups
; -x------ ; 6, 1=/, int edge select bit
; --x----- ; 5, timer0 source, 0=internal clock, 1=ext pin.
; ---x---- ; 4, timer0 ext edge, 1=\
; ----x--- ; 3, prescaler assign, 1=wdt, 0=timer0
; -----x-- ; 2,1,0, timer0 prescaler rate select
; ------x- ; 000=2, 001=4, 010=8, 011=16, etc.
; -------x ;
;
banksel OPTION_REG ; go proper reg bank
movwf OPTION_REG ; load data into OPTION_REG
banksel 0 ;
;-------------------------------------------------
; note! check for 16F628 (and A) and do extra setup for it.
IFDEF __16F628
banksel VRCON ; do bank 1 stuff
clrf VRCON ; disable Vref
clrf PIE1 ; disable pi etc
banksel 0 ;
clrf T1CON ; disable timer1
clrf T2CON ; disable timer2
clrf CCP1CON ; disable CCP module
movlw b'00000111' ; disable comparators
movwf CMCON ;
ENDIF
IFDEF __16F628A
banksel VRCON ; do bank 1 stuff
clrf VRCON ; disable Vref
clrf PIE1 ; disable pi etc
banksel 0 ;
clrf T1CON ; disable timer1
clrf T2CON ; disable timer2
clrf CCP1CON ; disable CCP module
movlw b'00000111' ; disable comparators
movwf CMCON ;
ENDIF
;-------------------------------------------------
; PORTB pins direction setup
; 1=input, 0=output
clrf PORTB ;
;
movlw b'00000000' ; all 8 portb are outputs
;
banksel TRISB ; go proper reg bank
movwf TRISB ; send mask to portb
banksel 0 ;
;-------------------------------------------------
; PORTA pins direction setup
; 1=input, 0=output
clrf PORTA ;
; NOTE!! all 5 PORTA pins are inputs
movlw b'00011111' ;
; ---x---- ; RA4
; ----x--- ; RA3
; -----x-- ; RA2
; ------x- ; RA1
; -------x ; RA0
banksel TRISA ; go proper reg bank
movwf TRISA ; send mask to porta
banksel 0 ;
;-------------------------------------------------
movlw 0x00 ; set up PCLATH for all jump tables on page 0
movwf PCLATH ; (all tables are in move_motor)
;-------------------------------------------------
; CLEAR RAM! for lower bank
movlw RAM_START ; first byte of ram
movwf FSR ; load pointer
ram_clear_loop
clrf INDF ; clear the ram we pointed to
incf FSR,f ; inc pointer to next ram byte
movf FSR,w ; get copy of pointer to w
sublw RAM_END ; test if PAST the last byte now
skpweq ;
goto ram_clear_loop ;
;-------------------------------------------------
; here we can set the user variables and output pins
movlw 0x00 ; for step 0 of 0-71
movwf step ; loaded ready for jump table
movf PORTA,w ; get initial value for inputs
movwf inputs ;
movwf inputs_last ;
;-------------------------------------------------
; set up INTCON register last
movlw b'00000000' ; set the bit value
; x------- ; bit7 GIE global int enable, 1=enabled
; -x------ ; bit6 EE write complete enable, 1=en
; --x----- ; bit5 TMR0 overflow int enable, 1=en
; ---x---- ; bit4 RB0/INT enable, 1=en
; ----x--- ; bit3 RB port change int enable, 1=en
; -----x-- ; bit2 TMR0 int flag bit, 1=did overflow and get int
; ------x- ; bit1 RB0/INT flag bit, 1=did get int
; -------x ; bit0 RB port int flag bit, 1=did get int
movwf INTCON ; put in INTCON register
;-------------------------------------------------
return ;
;------------------------------------------------------------------------------
;==============================================================================
; this code is only to display 1k of the memory usage chart
; in the absolute listing!
; page 0 256 byte block--------------------
;org 0x40-2
;nop
;org 0x80-1
;nop
;org 0xC0-1
;nop
;org 0x100-1
;nop
; page 1 256 byte block--------------------
;org 0x140-2
;nop
;org 0x180-1
;nop
;org 0x1C0-1
;nop
;org 0x200-1
;nop
; page 2 256 byte block--------------------
org 0x240-2
nop
org 0x280-1
nop
org 0x2C0-1
nop
org 0x300-1
nop
; page 3 256 byte block--------------------
org 0x340-2
nop
org 0x380-1
nop
org 0x3C0-1
nop
org 0x400-1
nop
IFDEF __16F628A
; page 4 256 byte block--------------------
org 0x440-2
nop
org 0x480-1
nop
org 0x4C0-1
nop
org 0x500-1
nop
; page 5 256 byte block--------------------
org 0x540-2
nop
org 0x580-1
nop
org 0x5C0-1
nop
org 0x600-1
nop
; page 6 256 byte block--------------------
org 0x640-2
nop
org 0x680-1
nop
org 0x6C0-1
nop
org 0x700-1
nop
; page 7 256 byte block--------------------
org 0x740-2
nop
org 0x780-1
nop
org 0x7C0-1
nop
org 0x800-1
nop
ENDIF
;-------------------------------------------------------------------------
end
;-------------------------------------------------------------------------
;==============================================================================
;==============================================================================
;==============================================================================
;-------------------------------------------------
; NOTE!! example! below is the original (non-pwm) table for the
; 24x hardware 6th steps.
; this will be useful to code a minimum-rom microstepper
; if you don't need 3600 and can make do with 1200 steps.
; same system as the main code;
; ----xxxx are the phase sequencing
; xxxx---- are the current values
; (this code table has been used and tested!)
;-------------------------------------------------
; COMMENTED OUT!
;movlw b'11000101' ; 0, 100,0 A+ B+ 00=0 01=25
;movlw b'11010101' ; 1, 100,25 A+ B+ 10=55 11=100
;movlw b'11100101' ; 2, 100,55 A+ B+
;movlw b'11110101' ; 3, 100,100 A+ B+
;movlw b'10110101' ; 4, 55,100 A+ B+
;movlw b'01110101' ; 5, 25,100 A+ B+
;-------------------------
;movlw b'00111001' ; 6, 0,100 A- B+
;movlw b'01111001' ; 7, 25,100 A- B+
;movlw b'10111001' ; 8, 55,100 A- B+
;movlw b'11111001' ; 9, 100,100 A- B+
;movlw b'11101001' ; 10, 100,55 A- B+
;movlw b'11011001' ; 11, 100,25 A- B+
;-------------------------
;movlw b'11001010' ; 12, 100,0 A- B-
;movlw b'11011010' ; 13, 100,25 A- B-
;movlw b'11101010' ; 14, 100,55 A- B-
;movlw b'11111010' ; 15, 100,100 A- B-
;movlw b'10111010' ; 16, 55,100 A- B-
;movlw b'01111010' ; 17, 25,100 A- B-
;-------------------------
;movlw b'00110110' ; 18, 0,100 A+ B-
;movlw b'01110110' ; 19, 25,100 A+ B-
;movlw b'10110110' ; 20, 55,100 A+ B-
;movlw b'11110110' ; 21, 100,100 A+ B-
;movlw b'11100110' ; 22, 100,55 A+ B-
;movlw b'11010110' ; 23, 100,25 A+ B-
EXAMPLE! full table example here, 0-71 steps showing every step...
;-------------------------
0 100,0 A+ B+
1 100,8 (pwm tween)
2 100,17 (pwm tween)
3 100,25 A+ B+
4 100,35 (pwm tween)
5 100,45 (pwm tween)
6 100,55 A+ B+
7 100,70 (pwm tween)
8 100,85 (pwm tween)
9 100,100 A+ B+ (rest of table is same, tweens not shown)
10
11
12 55,100 A+ B+
13
14
15 25,100 A+ B+
16
17
;-------------------------
18 0,100 A- B+
19
20
21 25,100 A- B+
22
23
24 55,100 A- B+
25
26
27 100,100 A- B+
28
29
30 100,55 A- B+
31
32
33 100,25 A- B+
34
35
;-------------------------
36 100,0 A- B-
37
38
39 100,25 A- B-
40
41
42 100,55 A- B-
43
44
45 100,100 A- B-
46
47
48 55,100 A- B-
49
50
51 25,100 A- B-
52
53
;-------------------------
54 0,100 A+ B-
55
56
57 25,100 A+ B-
58
59
60 55,100 A+ B-
61
62
63 100,100 A+ B-
64
65
66 100,55 A+ B-
67
68
69 100,25 A+ B-
70
71
;-------------------------------------------------