Linistepper Custom Software Mod

by Hazimin Fauzi

Quadrature input Linistepper in SDCC^ C

Note: This C code is not an exact replacement for the current, well tested, production Linistepper asm code, which you will find on the main page (click on "Linistepper" above). The differences are:

Hazimin says:

The good thing with quadrature is your step can be as fast as your parallel-port. With step/dir, each step need to toggle between '1' and '0', so speed is cut by two. Also, it's possible to detect a single miss steps with quadrature, as it is a form of Gray-code. it's an advantage if :
- Slow PC. To make 1200 steps per second, pc need to toggle the 1 single bit for 1200 time in 1 second. With quadrature, it only need to toggle 2 bit, each for 600time/seconds (2x600=1200 step).
- Slow PIC (the case of this code that is). If the PC is too fast, miss steps can happen. With quadrature, it can detect 1 miss steps (though it do nothing right now. Should be easy to trigger fault, etc).
And because quadrature signal doesn't return zero (NRZ), user doesn't need to mess with stepspace (min time for '1'), steplength (min time for '0'), etc.

Reason for eeprom:
- most pic have it and end up not used anyway.
- speed wise, it's similar to reading from array in flash. (i don't see any datasheet about flash vs eeprom data access, so this is my assumption)
- the only way to improve speed is to follow just like what you did in assembly, make switch case, then declare the value 1 by 1.
- the other "unrelated" reason is to make it tunable. For example, use serial port to change the value, etc (eeprom is writable on runtime).

The bad things:

1) The source code looks "hack"ish. This is due to:
- My incompetence
- SDCC workaround.

2) The code generated by SDCC is slow. It insert BANKSEL instruction every here and there. I've included hand edited assembly generated by SDCC to remove this unnecessary call, just as an example on how to improve further.

3) It's slower than the original linistepper in asm. With linistepper-asm, there's only ~20us delay before it output a new motors' current value. With SDCC compiled code, there's around ~50us before it output a new motors' current value. By editing the sdcc code and remove unneeded BANKSEL, "thinking" time now drop from 50us to ~30us.

4) It might have bugs. This software is still untested by many, so there's probably a few bugs creeping inside. If you find any, please update it here so we can share the fixes.

Also:

See:

See also:

/**
* LiniStepper-quadrature.c - stepper motor driver board for PIC16F628A
*
*  Copyright (C) 2011 Hazimin Fauzi <hazimin@gmail.com>
*  Copyright (C) 2011 Roman Black   <http://www.romanblack.com>
* 
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Permission is hereby granted, free of charge, to any person obtaining a 
* copy of this software and associated documentation files (the “Software”),
* to deal in the Software without restriction, including without limitation 
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the 
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be 
* included in all copies or substantial portions of the Software.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* LiniStepper.c Changelog
* 	- Literal conversion from assembly to C
* 	- Move high/low power table from code to EEPROM lookup
* 	- Ignore ENABLE pin input. 
* 	- Use step signal timeout to switch between low and high power. 
* 	- Store stepping table to EEPROM.
* 	- Use inline assembly for pwm loop
* 	- Disable runtime stepping mode change. 
* 	- Stepping mode is initialized on startup only to improve calculation time between step. 
* 	- Use quadrature input instead of STEP/DIR
*
* Based on LiniStepper.asm v1.0
* Copyright Aug 2002 Roman Black   http://www.romanblack.com
*
* PIC assembler code for the LiniStepper stepper motor driver board.
* 200/400/1200/3600 steps
*
* LiniStepper.asm Changelog
* v1.0	Seems to be working ok for now, few minor things need improving;
*		* touch up phase switching for direction -> 0
*		* table system is messy, can reduce in size a LOT if needed
*		* low-power mode doesn't microstep, only halfstep
*		* no easy way to step motor from within PIC softweare
*
*/

#include "pic16f628a.h"

unsigned int __at 0x2007 __CONFIG = _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _BODEN_OFF & _LVP_OFF;

// Switch to low power after TIMEOUT x 128milisecond 
#define TIMEOUT		10

// Stepping mode
#define MODE_3600	0b0011
#define MODE_1200	0b0010
#define MODE_400	0b0001
#define MODE_200	0b0000

/** Input pinout
* ---x----	RA4	* mode bit1	( 10=1200 step	11=3600 step
* ----x---	RA3	* mode bit0	 00=200 step	01=400 step )
* -----x--	RA2	* power		(ignored, use timeout instead)
* ------x-	RA1	* direction
* -------x	RA0	* step 
*/
#define MASK_MODE1	0b00010000
#define MASK_MODE0	0b00001000
#define MASK_POWER	0b00000100
#define MASK_B	0b00000010
#define MASK_A	0b00000001

// Overflow bit for step calculation
#define STEP_OVERFLOW	0b10000000

// Relative Address of high power table from EEPROM
#define ADDR_POWER_HI	0x00

// Relative Address of low power table from EEPROM
#define ADDR_POWER_LO	2 * 36 + ADDR_POWER_HI 

// Relative Address of stepping table from EEPROM
#define ADDR_STEPPING	36 + ADDR_POWER_LO 

// Column of stepping table as formatted in EEPROM
#define TBL_STEP_MIN	0
#define TBL_STEP_MAX	1
#define TBL_STEP_INC	2

/**
 * Correct sequence for reading the EEPROM is:
 * @ Set address
 * @ Set RD bit
 * @ Read value from EEDATA
 *
 * This expression does exactly that, first setting EEADR and RD
 * before returning the value of EEDATA.
 * 
 * Source: http://burningsmell.org/pic16f628/src/0009-eeprom.c
 */
#define EEPROM_READ(ADDR) (EEADR=ADDR,RD=1,EEDATA)

/**
 * NOTE: This variable must be store in BANK 0 for pwm_loop to works.
 * SDCC 3.0 crash with internal compiler error when absolute addressing is used.
 * Workaround: use linker trick. 
 * See section "UDL_linistepper_0" in 16f628a.lkr to define RAM address
 */
__data static unsigned char inputs;		// store new input pins
__data static unsigned char inputs_last;	// store last states of input pins

__data static unsigned char current1;		// for current tween pwm
__data static unsigned char current2;		// for current tween pwm
__data static unsigned char phase;		// stores the 4 motor phase pins

volatile __data static unsigned char timer_count;	// count timer1 overflow for larger delay 
							// NOTE: declared volatile due to sdcc optimizer 
							// can't track value changed from inline assembly

__data static unsigned char step;		// (0-71) ustep position
__data static unsigned char steptemp;		// for step calcs

__data static unsigned char mode;		// store stepping mode

__data static unsigned char eeprom_addr;	// for eeprom table lookup (max addressable=0xff)

__data static unsigned char step_max;		// max step for selected mode
__data static unsigned char step_min;		// min step for selected mode
__data static unsigned char step_inc;		// step increment for selected mode

__data static unsigned char phase_a;			// for calcs
__data static unsigned char phase_b;			// for calcs
  

void handler(void) __interrupt 0 {
  // put additional interrupt code here...
} 

/**
* pwm() the fast pwm 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 modified code here was originally supplied by Eric Bohlman (thanks!)
*
* Code below is the equivalent pwm_loop in C (without timeout count).
* (SDCC 3.0) :	~24 cycles for current2, 
* 		~12 cycles for current1 
* 
* do {
*    PORTB = current2;    			// send current2 to motor
*    inputs = PORTA;      			// read input
*    if((inputs_last ^ inputs) & ~MASK_POWER) {	// break loop except power pin change      
*      break;
*    }  
*    PORTB = current1;				// send current1 to motor
*  } while (!TMR1IF);				// loop unless input timeout
* 
*/
static void pwm(void) {    
  timer_count = TIMEOUT;			// reload delay counter
  TMR1H = 0;					// reset timer value
  TMR1L = 0;  
  /* T1CON 
  ;  x-------		; bit7 	unimplemented
  ;  -x------		; bit6	unimplemented
  ;  --x-----		; bit5 	TMR1 prescale (10=1:4, 11=1:8)
  ;  ---x----		; bit4 	TMR1 prescale (00=1:1, 01=1:2)
  ;  ----x---		; bit3	timer 1 osc (0=osc on, 1=osc off)
  ;  -----x--		; bit2	tmr1 sync (ignored when tmr1 source=0)
  ;  ------x-		; bit1	tmr1 source (0=internal, 1=external)
  ;  -------x		; bit0	tmr1 on (1=on, 0=off) */
  T1CON=0b00110001;				// start timer 1 with prescaler 1:8  
  __asm						// NOTE:make sure we're already in BANK0 before start 
   pwm_loop:					// main entry!
						// better to enter at current2 for motor power.
     movf _current2,w				// output current2 to motor     
     movwf PORTB				// send to motor! 
     nop					// (8 cycle for current2)
     btfsc PIR1,0				// check for timer1 overflow            
     goto pwm_timeout
						// now test input pins
     movf PORTA,w				// get pin values from port       
     xorwf _inputs_last,w			// xor to compare new inputs with last values
     andlw b'00000011'				// only check for step change (MASK_A | MASK_B)
     skpz					
     goto pwm_final				// not zero, one or more input pins have changed!
						// else, output current1 to motor
     movf _current1,w				// get currents and phase switching
     movwf PORTB				// send to motor! (4 cycles for current1)
     goto pwm_loop				// keep looping
   pwm_final:
     xorwf _inputs_last,w			
     movwf _inputs				// restore xored value back to the orig inputs value  
     goto pwm_exit
   pwm_timeout: 				// count how many time timer1 have overflow
     bcf PIR1,0					// clear timer1 overflow flag
     decfsz _timer_count,f			// loop until timer_count reach zero     
     goto pwm_loop				
     btfss _inputs,2				// continue loop, already in low power
     goto pwm_loop
   pwm_exit:
  __endasm;  
  
  if(!timer_count) {
    inputs &= ~MASK_POWER;			// drop to low power
  } else {        
    inputs |= MASK_POWER;			// turn on high power
  }  
  TMR1ON = 0;      				// stop the timer
}

/**
*  new_inputs()   input change was detected
*
* when we enter here:
* - inputs have just changed
* - inputs_last	contains last PORTA inputs values
* - inputs	contains new PORTA inputs values
*
* Quadrature is simply 2 bit gray code
* Only 1 bit is changed for every step
* Forward sequence = AB:00->01->11->10->00->01...
*/
static void new_inputs(void) {     
  phase_a = (inputs & MASK_A);			// phase_a=1 if A=1, else 0
  phase_b = (inputs & MASK_B) >> 1;		// phase_b=1 if B=1, else 0
  if((inputs ^ inputs_last) & MASK_A) {		// Check if A changed from previous
    if((inputs ^ inputs_last) & MASK_B) {	// A changed from previous. Check for B 
      // invalid state or missing step 00->11, 11->00, 01->10, 10->01
      // B should not change in single step
      // TODO: trigger fault/emergency stop, etc
    } else if(phase_b == phase_a) { 		
      step += step_inc;				// forward AB:10->00 or 01->11
    } else {
      step -= step_inc;				// reverse AB:00->10 or 11->01         
    }
  } else {
    if((inputs ^ inputs_last) & MASK_A) {	// B changed from previous, Check for A 
      // invalid state or missing step 00->11, 11->00, 01->10, 10->01
      // A should not change in single step
      // TODO: trigger fault/emergency stop, etc
    } else if(phase_b == phase_a) { 		
      step -= step_inc;				// reverse AB:10->11 or 01->00      
    } else {					 
      step += step_inc;				// forward AB:11->10 or 00->01      
    } 
  }
  if(step & STEP_OVERFLOW) {		// test for roll under <0	    
    step = step_max;			// rolled under so force to max step
  } else if(step > step_max) {			// test for roll over >max step
    step = step_min;			// rolled over so force to step minimum
  } 
  inputs_last = inputs;				// save a copy of the inputs
}

/**
* move_motor() 	sets 8 output pins to control motor
*
* 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
*
*
*/
static void move_motor(void) {
  steptemp = step;				// find which of the 4 ranges we are in 
  if(steptemp - 35 > 0) {			// step is between 36-71   
    steptemp -= 36; 				
    if(steptemp - 17 > 0) {			// step is in range 3
      phase = 0b00000110;			// 0110 = A+ B-
    } else {      				// step is in range 2
      phase = 0b00001010;			// 1010 = A- B-
    }    
  } else {    					// step is between 0-35
    if(steptemp - 17 > 0) {			// step is in range 1
      phase = 0b00001001;			// 1001 = A- B+
    } else {					// step is in range 0
      phase = 0b00000101;			// 0101 = A+ B+
    }
  }
  /*-------------------------------------------------
  ; 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 reading from EEPROM.

  ; as we have 2 power modes; full and low power, we need 2 tables.
  -------------------------------------------------*/	
  if(inputs & MASK_POWER) {			// high power selected    
    eeprom_addr = (steptemp + steptemp) + ADDR_POWER_HI;
    current2 = phase | EEPROM_READ(eeprom_addr);
    current1 = phase | EEPROM_READ(eeprom_addr + 1);
    
  } else {					// low power is selected
    eeprom_addr = steptemp + ADDR_POWER_LO;
    current2 = phase | EEPROM_READ(eeprom_addr);
    current1 = current2;     
  }  
}

/**
*  setup()   sets port directions and interrupt stuff etc,
*/
static void setup(void) {  
  /* OPTION_REG
  ;  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		; */
  OPTION_REG = 0b10000010;
  TRISA = 0b00011111;				// all 5 port A pins are inputs (1=input, 0=output)  
  TRISB = 0;					// all 8 port B are outputs (1=input, 0=output)
  VRCON = 0;					// disable Vref
  /* INTCON 
  ;  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 */
  INTCON=0;  
  PIE1 = 0;					// disable pi etc
  T1CON = 0;					// disable timer1
  T2CON = 0;					// disable timer2
  CCP1CON = 0;					// disable CCP module
  CMCON = 0b00000111;				// disable comparators
  PORTB = 0;					// clear PORTB   
  PORTA = 0;					// clear PORTA    
  step = 0;					// reset step value  
  inputs_last = 0;  
  inputs = PORTA;				// get initial value for inputs  
  mode = (inputs & (MASK_MODE1 | MASK_MODE0)) >> 3;	// find which of the 4 modes we are in
  eeprom_addr = (mode + mode + mode) + ADDR_STEPPING;	// each mode store 3 value: min,max,increment
  step_inc = EEPROM_READ(eeprom_addr + TBL_STEP_INC);
  step_min = EEPROM_READ(eeprom_addr + TBL_STEP_MIN);
  step_max = EEPROM_READ(eeprom_addr + TBL_STEP_MAX);      
}

/**
*  Main 
*/
void main(void) {
  setup();					// do initial setup for ports and ints and stuff
  while(1) {     						
    move_motor();				// will set the motor current based on step value
    pwm();					// move the motor and loop until input changed 
    new_inputs(); 				// read new inputs and set the step value    
  }

}               

Because SDCC can't read EEPROM tables directly, the step table data is provided as a seperate asm file:

;
; eepromtbl.asm  - A collection of data definition to be stored in eeprom
;
;  Copyright (C) 2011 Hazimin Fauzi <hazimin@gmail.com>
;  Copyright (C) 2011 Roman Black   <http://www.romanblack.com>
;
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Permission is hereby granted, free of charge, to any person obtaining a 
; copy of this software and associated documentation files (the “Software”),
; to deal in the Software without restriction, including without limitation 
; the rights to use, copy, modify, merge, publish, distribute, sublicense,
; and/or sell copies of the Software, and to permit persons to whom the 
; Software is furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be 
; included in all copies or substantial portions of the Software.
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


	list    p=16f628a
	include "p16f628a.inc"
	org 0x2100	; change this to eeprom address of your processor


	;-------------------------------------------------
	; HIGH POWER TABLE
	;-------------------------------------------------
	; here are the 36 value pairs 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 value pairs set the 2 currents desired, then
	; loaded to a fast-pwm loop (same loop used for all currents)
	; which modulates between the 2 currents and gives final
	; output current.
	;-------------------------------------------------
	; High Power Table				current: current2 : current1
	de b'11000000',b'11000000' ; 00: (6th step),	current: 100,000 : 100,000 
	de b'11000000',b'11010000' ; 01: (tween step),	current: 100,000 : 100,025
	de b'11010000',b'11000000' ; 02: (tween step),	current: 100,025 : 100,000
	de b'11010000',b'11010000' ; 03: (6th step),	current; 100,025 : 100,025
	de b'11010000',b'11100000' ; 04: (tween step),	current: 100,025 : 100,055
	de b'11100000',b'11010000' ; 05: (tween step),	current: 100,055 : 100,025
	de b'11100000',b'11100000' ; 06: (6th step),	current; 100,055 : 100,055
	de b'11100000',b'11110000' ; 07: (tween step),	current: 100,055 : 100,100
	de b'11110000',b'11100000' ; 08: (tween step),	current: 100,100 : 100,055
	de b'11110000',b'11110000' ; 09: (6th step),	current; 100,100 : 100,100
	de b'11110000',b'10110000' ; 10: (tween step),	current: 100,100 : 055,100
	de b'10110000',b'11110000' ; 11: (tween step),	current: 055,100 : 100,100
	de b'10110000',b'10110000' ; 12: (6th step),	current; 055,100 : 055,100
	de b'10110000',b'01110000' ; 13: (tween step),	current; 055,100 : 025,100
	de b'01110000',b'10110000' ; 14: (tween step),	current; 025,100 : 055,100
	de b'01110000',b'01110000' ; 15: (6th step),	current; 025,100 : 025,100
	de b'01110000',b'00110000' ; 16: (tween step),	current; 025,100 : 000,100
	de b'00110000',b'01110000' ; 17: (tween step),	current; 000,100 : 025,100
	de b'00110000',b'00110000' ; 18: (6th step),	current; 000,100 : 000,100
	de b'00110000',b'01110000' ; 19: (tween step),	current; 000,100 : 025,100
	de b'01110000',b'00110000' ; 20: (tween step),	current; 025,100 : 000,100
	de b'01110000',b'01110000' ; 21: (6th step),	current; 025,100 : 025,100
	de b'01110000',b'10110000' ; 22: (tween step),	current; 025,100 : 055,100
	de b'10110000',b'01110000' ; 23: (tween step),	current; 055,100 : 025,100
	de b'10110000',b'10110000' ; 24: (6th step),	current; 055,100 : 055,100
	de b'10110000',b'11110000' ; 25: (tween step),	current; 055,100 : 100,100
	de b'11110000',b'10110000' ; 26: (tween step),	current; 100,100 : 055,100
	de b'11110000',b'11110000' ; 27: (6th step),	current; 100,100 : 100,100
	de b'11110000',b'11100000' ; 28: (tween step),	current; 100,100 : 100,055
	de b'11100000',b'11110000' ; 29: (tween step),	current; 100,055 : 100,100
	de b'11100000',b'11100000' ; 30: (6th step),	current; 100,055 : 100,055
	de b'11100000',b'11010000' ; 31: (tween step),	current; 100,055 : 100,025
	de b'11010000',b'11100000' ; 32: (tween step),	current; 100,025 : 100,055
	de b'11010000',b'11010000' ; 33: (6th step),	current; 100,025 : 100,025
	de b'11010000',b'11000000' ; 34: (tween step),	current; 100,025 : 100,000
	de b'11000000',b'11010000' ; 35: (tween step),	current; 100,000 : 100,025  



	;-------------------------------------------------
	; 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!! This table is truncated to single value due to out of space in EEPROM
	; Expand to value pairs if you want to use full size table.
	;-------------------------------------------------      
	; current 	: current1 = current2
	de b'10010000'	; 0-8: current: 55.25
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'01100000'	; 9-17: current 25.55
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'	; 18-26: current 25.55
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'01100000'
	de b'10010000'	; 19-26: current 55.25
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'
	de b'10010000'

	;-------------------------------------------------
	; STEPPING TABLE
	;-------------------------------------------------
	; This table store stepping value for various mode
	; Mode 00 : 200 steps (72/18),4 valid step: 9,27,45,63
	; Mode 01 : 400 steps (72/9),8 valid step: 4,13,22,31,40,49,58,67
	; Mode 10 : 1200 steps (72/3), valid step is mod 3 (0,3,6,9 etc)
	; Mode 11 : 3600 steps (72/1), step increment by 1
	;-------------------------------------------------
	; step min, step max, step increment 
	de d'9',d'63',d'18'
	de d'4',d'67',d'9'
	de d'0',d'69',d'3'
	de d'0',d'71',d'1'
	end