;***************************************************************************
;******
;****** PIC12F675. TCI ignition
;****** 
;****** SPORTDEVICES AUG/19/2009
;******
;****** Tested on Kymco MXU250 ATV
;******
;****************************************************************************

	list     p=12F675
	#include p12F675.inc
	radix dec

	__CONFIG	_HS_OSC & _WDT_OFF & _MCLRE_OFF & _PWRTE_ON

;setup values

#define prescaler        8     ;2^8=256
#define dwell_time       5000  ;us
#define delay_multiple   8     ;8 us, min 3 us
#define max_rpm          9000  ;max rpm value
#define idle_rpm         2000  
#define min_rpm          200   ;min rpm value, if lower the program starts again

#define rpm_cte          60*10000000/4/256
#define idle             rpm_cte/idle_rpm
#define min_period       rpm_cte/max_rpm
#define max_period       rpm_cte/min_rpm   ;(2^prescaler)
#define dwell_constant   dwell_time/102    ;1e6 /(10e6 / 4 / 256)

#define pickup_hi    GPIO,3  ;pin 4
#define pickup_lo    GPIO,2  ;pin 5
#define coil         GPIO,1  ;pin 6

#define low_rpm      pack,0
#define hi_rpm       pack,1

   cblock 0x20 ;first free memory address!!!
     del,delh,per,perh,dwell,dwellh,tmr0h,pack
     tmp,tmph
     W_TEMP,STATUS_TEMP
   endc

   org 0x00
     MOVLW  00
     MOVWF  0x0A
     GOTO   MAIN ;0A8

   org 0x04
     MOVWF  W_TEMP
     SWAPF  STATUS,W
     MOVWF  STATUS_TEMP

     BTFSS  INTCON,INTF
     GOTO   L24
;low pulse
ext:
     BCF    coil         ;fire or turn off the coil
     BCF    INTCON,INTF
;**

L24: BTFSS  INTCON,T0IF
     GOTO   L25

timer0:
     INCF   tmr0h,F

     MOVF   tmr0h,W      ;  if(tmr0h>2) low_rpm=true;
     SUBLW  02
     BTFSS  STATUS,C
     BSF    low_rpm      ;low_rpm=true;

     MOVF   tmr0h,W      ;if(tmr0h>(max_period/256)) 
     SUBLW  max_period/256
     BTFSS  STATUS,C
     BCF    coil         ;  output_low(coil); ;turn off the coil (residual spark will be made)
     
     BCF    INTCON,T0IF
;**

L25: SWAPF  STATUS_TEMP,W
     MOVWF  STATUS
     SWAPF  W_TEMP,F
     SWAPF  W_TEMP,W
     RETFIE





read_array:
     addwf  PCL,f
ignition_start:
     ;9000 rpm
     retlw 20
     retlw 21
     retlw 22
     retlw 23
     retlw 24
     retlw 25
     retlw 26
     retlw 27
     ;8000 rpm
     retlw 28
     retlw 29
     retlw 33
     retlw 38
     retlw 44
     retlw 50
     retlw 55
     retlw 60
     retlw 65
     retlw 70
     ;7000 rpm
     retlw 69
     retlw 74
     retlw 77
     retlw 80
     retlw 81
     retlw 82
     retlw 83
     retlw 84
     retlw 85
     retlw 86
     retlw 87
     retlw 89
     retlw 91
     retlw 93
     ;6000 rpm
     retlw 97
     retlw 100
     retlw 103
     retlw 107
     retlw 113
     retlw 119
     retlw 124
     retlw 131
     retlw 137
     retlw 140
     retlw 145
     retlw 150
     retlw 157
     retlw 160
     retlw 165
     retlw 170
     retlw 175
     retlw 176
     retlw 177
     retlw 178
     ;5000 rpm
ignition_end:
;....................


wait_pulse:
L83: BTFSC  pickup_hi    ;while (input(pickup_hi));   ;wait line goes low
     GOTO   L83

;wait dwell
     BTFSC  low_rpm      ;if(!low_rpm)
     GOTO   L8C
     BTFSC  hi_rpm      ;&&(!hi_rpm)
     GOTO   L8C
waitd:
;{  
do:  MOVF   tmr0h,W     ;  tmp=make16(tmr0h,TMR0);  
     MOVWF  tmph
     MOVF   TMR0,W
     MOVWF  tmp

     MOVF   tmph,W      ;while((tmp<dwell) && !input(pickup_hi));  
     SUBWF  dwellh,W
     BTFSS  STATUS,C
     GOTO   endwhile
     BTFSS  STATUS,Z
     GOTO   L09A
     MOVF   dwell,W
     SUBWF  tmp,W
     BTFSC  STATUS,C
     GOTO   endwhile
L09A:BTFSS  pickup_hi
     GOTO   do
endwhile:
     BSF    coil        ;output_high(coil); ;start dwell time now

L8C: CLRF   pack         ;hi_rpm=false; low_rpm=false

L8D: BTFSS  pickup_hi    ;while (!input(pickup_hi));  ;wait line goes high
     GOTO   L8D

     MOVF   tmr0h,W      ;perh=TMR0h
     MOVWF  perh
     MOVF   TMR0,W       ;per=TMR0
     MOVWF  per

     CLRF   TMR0
     CLRF   tmr0h

     MOVF   perh,F       ;if (per<min_period)
     BTFSS  STATUS,Z
     GOTO   nomin
     MOVF   per,W        
     SUBLW  min_period-1
     BTFSS  STATUS,C
     GOTO   nomin
     BSF    hi_rpm       ;  hi_rpm=true;
     GOTO   LB1          ;else
nomin:
     BSF    coil         ;  output_high(coil); ;start dwell time (if not started yet)
LB1:

     GOTO   rtn          ;RETURN


MAIN:
     MOVLW  07           ;init GPIO (digital)
     ANDWF  CMCON,F
     BSF    STATUS,RP0
     CLRF   ANSEL
     BCF    STATUS,RP0
      
     MOVLW  0x40 | prescaler-1  ;PULLUP on, 2^prescaler=128
     BSF    STATUS,RP0
     MOVWF  OPTION_REG
     MOVLW  B'11111101'
     TRIS   GPIO
     BCF    STATUS,RP0

     CLRF   tmr0h
     BSF    low_rpm      ;low_rpm=TRUE

     MOVLW  B'10110000'  ;T0IE=1,INTE=1
     MOVWF  INTCON



MAIN_LOOP:
;first pulse is not processed because the period can not be calculated until the second pulse
LBD: GOTO   wait_pulse
rtn: BTFSC  low_rpm           ;do wait_pulse(); while(low_rpm);
     GOTO   LBD

     MOVF   perh,W             ;dwell=per;  
     MOVWF  dwellh
     MOVF   per,W
     MOVWF  dwell

     BTFSC  hi_rpm            ;if (!hi_rpm)
     GOTO   nofire

     MOVF   perh,F	      ;if(per<(sizeof(ignition)+min_period)
     BTFSS  STATUS,Z
     GOTO   low_range
     MOVF   per,W             
     SUBLW  ignition_end-ignition_start+min_period-1
     BTFSS  STATUS,C
     GOTO   low_range

     MOVLW  min_period        ;del=ignition0[per-minperiod];
     SUBWF  per,W
     CALL   read_array        
     MOVWF  del

;do delay
loop:NOP                      ;delay_cycles(delay_multiple-3);
     NOP
     NOP
     NOP
     NOP
     DECFSZ del,f
     GOTO   loop
     GOTO   nofire
;}else{
low_range:
     MOVF   perh,W       ;if(per>idle) 
     SUBLW  (idle >> 8)-1
     BTFSC  STATUS,C
     GOTO   midle
     XORLW  0xFF
     BTFSS  STATUS,Z
     GOTO   mult
     MOVF   per,W
     SUBLW  (idle & 0xff)
     BTFSC  STATUS,C
     GOTO   midle     
mult:
     BCF    STATUS,C     ; per=per<<1;
     RLF    per,F
     RLF    perh,F

midle:
     INCF   perh,F
     INCF   per,F
loop2:
     NOP                 ;delay_cycles(9);
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     DECFSZ per,F
     GOTO   loop2
     DECFSZ perh,F
     GOTO   loop2
;}

nofire:
     BTFSS  low_rpm           ;if(!low_rpm)
     BCF    coil              ;  output_low(coil); ;fire or turn off the coil

     MOVLW  dwell_constant & 0xff ;dwell-=(unsigned int16)dwell_constant;
     SUBWF  dwell,F
     MOVLW  (dwell_constant >> 8)
     BTFSS  STATUS,C
     MOVLW  (dwell_constant >> 8)+1
     SUBWF  dwellh,F

;silent_time, 768 us (256*3)
     CLRF   del
silent:
     DECFSZ del,F
     GOTO   silent

     GOTO   MAIN_LOOP

     END
