;**************************************************************************
;* FileName	: PC1F.ASM
;* Date 	: 04.10.2004
;* File version : v1.02
								list l=0
;* Author	: MIKO, Imre
;* Company	:
;* Homepage	: http://majki.fw.hu
;* E-mail	: majki@fw.hu
;*
;*-------------------------------------------------------------------------
;*
;* Description	: 1 phase power controller with 2 antiparallel thyristors
;*		  =======================================================
;*		  
;*                    ^ Ufx
;*                    |		  
;*                    |     _--_                      _--_
;*                    |    /    \                    /    \
;*                    |   |      \                  |      \
;*                    |   |       \                 |       \
;*                    |   |        |                |        |               t
;*                   =+===+--------+===+========+===+--------+===+========+===>
;*                    |                |        |                |        |
;*                    |                |       /                 |       /
;*                    |                |      /                  |      /
;*                    |                 \    /                    \    /
;*                    |                  ^--^                      ^--^
;*                    |            |            |            |             
;*                    0           10           20           30             (ms)
;*                    0          10000       20000        30000            (RE)
;*                                                           
;*                    ^ Ug                                   
;*                    |                                      
;*                    |   +-------+    +-------+    +-------+    +-------+
;*                    |   |       |    |       |    |       |    |       |   t(ms)
;*                   =+===+-------++===+-------++===+-------++===+-------++===>
;*		          a   a+2      b   b+2	    c   c+2      d   d+2
;* 				            
;* 
;*
;*                1    +----------+              +----------+
;*                0 --++          ++------------++          ++---------- ZERO
;*
;*
;*		  Time is calculated in RE (resolution element):
;*
;*                  1 RE      = 1 uS
;*                  1 periode = 20000 RE = 360 degree =  20000 uS
;*                  1 degree  = 55.555 RE = 55.555 uS
;*		    1 mS      = 1000 RE
;*
;*
;*-------------------------------------------------------------------------
;*
;* Connections	:	       ________	  ________
;*			      |        \_/	  |
;*			+5V ==| Vdd	      Vss |== GND
;*		       OSC1 ==| GP5/OSC1      GP0 |== POTMETER
;*		       OSC2 ==| GP4/OSC2      GP1 |== MINANGLE
;*		       ZERO ==| GP3/-MCLR     GP2 |== GATE
;*			      |___________________|
;*				    PIC12F675
;*
;*-------------------------------------------------------------------------
;*
;* Resource	: Ports 	  :     6 /    6 pin   (100%)
;*		  Data memory	  :    26 /   64 byte  ( 40%)
;*		  Prog memory	  :   543 / 1024 word  ( 53%)
;*		  EEPROM	  :     0 /  128 byte  (  0%)
;*		  Timers	  : TMR0, TMR1
;*		  Interrupt	  : -
;*		  Comparator	  : -
;*
;**************************************************************************
;* Revision History:
;*
;* 1.00	  26/08/2004 	Initial Release
;*
;* 1.01   12/09/2004    - fix fatal AD bug (in adc.mac)
;*                      - change some timeing parameter
;*                      - hysteresis type free time switch
;*			- startup delay time for eliminate transient
;*
;* 1.02   04/10/2004    - change some timeing parameter
;*
;**************************************************************************

	list	p=12f675, r=dec, l=0

;***** INCLUDES ***********************************************************

	include "p12f675.inc"
	include "..\..\..\modules\base.inc"

;***** CONFIG ************************************************************

CFG_1	EQU 	_XT_OSC & _WDT_ON & _PWRTE_ON & _MCLRE_OFF
CFG_2	EQU	_BODEN_ON & _CP_ON & _CPD_OFF
CFG_3   EQU     01000111111111b			; unimplemented bits + BG0-BG1


	__CONFIG CFG_1 & CFG_2 & CFG_3
	__IDLOCS 0102h				; version

	EXPAND_MACROS	EXP_COND		; macro expansion mode
	MULTIPAGE	1, 2048, 2		; support for multipage program memory

;***** DEFINES ************************************************************
;#define DEBUG					; for some debug message
;#define NO_DELAY				; for fast simulation
;#define NO_RS232				; for fast simulation

xtal_freq	EQU	4 MHz	  		; crystal frequency
core_freq	EQU	xtal_freq/4		; core operating frequency


; ----- GPIO --------------------------------------------------------------

#define		POTMETER	GPIO,0		; analog in
#define		MINANGLE	GPIO,1		; analog in
#define		GATE		GPIO,2		; out
#define		ZERO		GPIO,3		; in (only input or -MCLR!)
#define		OSC2		GPIO,4		; osc2 (IO or OSC2)
#define		OSC1		GPIO,5		; osc1 (IO or OSC1)

; ----- analog ports ------------------------------------------------------

#define		AD_POTMETER	AD_CH0
#define		AD_MINANGEL	AD_CH1

; ----- module defines ----------------------------------------------------
#define MATH_OPTSPEED				; multiply speed optimalisation
#define	AD_WITH_ANSEL				; device with ANSEL register


;***** MACROS *************************************************************

	include "..\..\..\modules\adc.mac"
	include "..\..\..\modules\wait.mac"
	include "..\..\..\modules\math.mac"
	include "..\..\..\modules\tmrx.mac"


;***** CONSTANT DEFINITIONS ***********************************************

option_val	EQU	10000010b		; Timer source : intclk / 8
tris_val	EQU	00111011b		; tris value (all input except GATE)
ansel_val       EQU     00000000b		; all input is digital -> it will be redefined by AD_INIT macro
wpu_val         EQU     00000000b		; weak pull ups all off
intcon_val	EQU	00000000b		; Interrupt off
cmcon_val	EQU	00000111b		; comparators off


; ----- defines -----------------------------------------------------------
#define	CONST_MIN_ALPHA		100		; RE =   2 degree (It should be grether as 50.)
#define	CONST_MAX_ALPHA		9350		; RE = 168 degree
#define	CONST_AVR_ALPHA		5000		; RE =  90 degree

#define	MIN_MINANGLE		CONST_MIN_ALPHA
#define	MAX_MINANGLE		5000		; RE = 90 degree

#define	CONST_MIN_HOLDTIME	150		; RE =  150 us

#define	CONST_RAMP_SLOPE	50		; total rising time = 2 seconds


; ----- flags -------------------------------------------------------------
#define	FLAG_BIGSETUPTIME	flags,0		; if set the setup time is greater as hold time



;***** VARIABLE DEFINITIONS ***********************************************
	cblock	20h
		w_temp				; variable used for context saving
		status_temp			; variable used for context saving
		fsr_temp			; variable used for context saving

		flags				; flags
		loopcounter		

		potmeter16:2			; potmeter state
		alphamin16:2			; max. power
		alphamax16:2			; min. power
		alpha16:2			; whished gate trigger delay time
		alpha_ramp16:2			; real gate trigger delay time
		hold16:2			; gate trigger hold time


	endc



;***** ENTRY POINT ********************************************************
		ORG	000h			; processor reset vector
		nop
		clrf	GPIO			; clear latch
		clrwdt
		goto	start



;***** IT HANDLER *********************************************************
;* Interrupt handler -> not used
;* <comment>
;**************************************************************************
		ORG	004h			; interrupt vector location
		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

		movf	FSR,w			; save FSR
		movwf	fsr_temp
;--------------------------------------------------------------------------

		; <IT Code>

;--------------------------------------------------------------------------
		movf	fsr_temp,w		; restore FSR
		movwf	FSR

		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



;***** REAL PROGRAM START *************************************************
start
;----- set configuration --------------------------------------------------
		bank1
		ERRORLEVEL -302
		movwf	OSCCAL				; store OSCCAL value
		movlw	option_val
		movwf	OPTION_REG			; set OPTION_REG
		movlw	tris_val
		movwf	TRISIO				; set TRISIO
		movlw	ansel_val	
		movwf	ANSEL				; set ANSEL
		movlw	wpu_val	
		movwf	WPU				; set WPU

		bank0
		ERRORLEVEL +302
		movlw	intcon_val	
		movwf	INTCON				; set INTCON
		movlw	cmcon_val	
		movwf	CMCON				; set CMCON


;----- module inits -------------------------------------------------------

		AD_INIT		AD_Fosc8 , AD_JUST_RIGHT, 00000011b

		TMR0_INIT	64			; timer for calculate zero crossing of negative periode (10mS)
		TMR1_INIT	1			; timer for measure gate setup and hold time


;----- inits --------------------------------------------------------------

		bcf	GATE				; set gate port off (no trigger for thyristors)
		clrf	flags
		bsf	FLAG_BIGSETUPTIME

		MOVC16	alphamax16,   (CONST_MAX_ALPHA - CONST_MIN_HOLDTIME)
		MOV16	alpha_ramp16, alphamax16

		call	read_alphamin			; read alpha minimum value
		call	read_potmeter			; read potmeter value
		call	calc_alpha			; calculate gate trigger delay time
		call	calc_hold			; calculate gate trigger hold time

;--------------------------------------------------------------------------

		MOVC8 loopcounter, 20			; 20 * 10 ms = 200 ms

startup_delay	clrwdt					; cycle for deletion of WDT
		WAIT	10 Millisec, 0
		decfsz	loopcounter,f
		goto	startup_delay

;----- main cycle  --------------------------------------------------------
main_cycle	clrwdt

;**************************************************************************
; ----- positive periode --------------------------------------------------
;**************************************************************************

mc_waitnotzero	btfsc	ZERO				; waiting for not zero crossing
		goto	mc_waitnotzero
		nop2
		btfsc	ZERO
		goto	mc_waitnotzero
		nop2
		btfsc	ZERO
		goto	mc_waitnotzero	

; -------------------------------------------------------------------------
mc_waitzero1	btfss	ZERO				; waiting for positive periode zero crossing
		goto	mc_waitzero1
		nop2
		btfss	ZERO
		goto	mc_waitzero1
		nop2
		btfss	ZERO
		goto	mc_waitzero1	

; -------------------------------------------------------------------------
		TMR0_START 9984 Microsec		; start TMR0 for negativ zero crossing
		nop					; after this nop: >>>>>  0 uS <<<<<

; -------------------------------------------------------------------------
		call	gate_trigger

		clrwdt

;**************************************************************************
; ----- negative periode --------------------------------------------------
;**************************************************************************

mc_waitzero2	TMR0_NOTOUT mc_waitzero2		; check TMR0 for negativ zero crossing	

		WAIT	13 Microsec, 0			; dummy delay for time matching
		nop					; after this nop: >>>>> 10000 uS (+-1) <<<<<

; -------------------------------------------------------------------------
		call	gate_trigger

		goto	main_cycle



;***** gate_trigger *******************************************************
;* wait setup time, fire the thyristor, wait hold time, "close" the thyristor
;* Input : -             		; 
;* Output: -				;
;* Clock : ca. 9.5mS    
;**************************************************************************
gate_trigger
	; ----- start TMR1 for setup time ---------------------------------

		movf	alpha_ramp16,w
		movwf	tmr1hi
		movf	alpha_ramp16+1,w
		TMR1_STARTW				; start TMR1 with gate trigger setup time			

	; ----- free time calculations ------------------------------------

		btfsc	FLAG_BIGSETUPTIME
		call	free_time			; calculation in free time

	; ----- test setup time -------------------------------------------

gt_waitsetup	TMR1_NOTOUT gt_waitsetup

		bsf	GATE				; fire the the thyristor

	; ----- start TMR1 for hold time ----------------------------------

		movf	hold16,w
		movwf	tmr1hi
		movf	hold16+1,w
		TMR1_STARTW				; start TMR1 with gate hold time


	; ----- free time calculations ------------------------------------

		btfss	FLAG_BIGSETUPTIME
		call	free_time			; calculation in free time

	; ----- test hold time --------------------------------------------

gt_waithold	TMR1_NOTOUT gt_waithold

		bcf	GATE				; not fire the thyristor

	; -----------------------------------------------------------------
		return




;***** free_time **********************************************************
;* Read AD, calculate alpha16, etc. in free time
;* Input : -             		; 
;* Output: -				;
;* Clock : ca. 350 uS     
;**************************************************************************
free_time	call	read_alphamin
		call	read_potmeter
		call	calc_alpha
		call	calc_hold
		return




;***** read_alphamin ******************************************************
;* Read MINANGLE analog input 
;* Input : -             		; 
;* Output: alphamin16 <-		; min. trigger delay in RE (0...6138 + MIN_MINANGLE)
;* Clock : ?  
;**************************************************************************
read_alphamin
		AD_GET	AD_MINANGEL
		movf	ADRESH,w
		movwf	alphamin16
		bank1
		ERRORLEVEL -302
		movf	ADRESL,w
		ERRORLEVEL +302
		bank0
		movwf	alphamin16+1

		SHL16	alphamin16		; alphamin16 = ADRES16 * 2

		MOV16	AARG16, alphamin16	; AARG16 = ADRES16 * 4
		SHL16	AARG16

		ADD16	alphamin16, AARG16	; alphamin16 = 6 * ADRES16
		ADDC16	alphamin16, MIN_MINANGLE

		return								




;***** read_potmeter ******************************************************
;* Read potmeter analog input 
;* Input : -             		; 
;* Output: potmeter16 <-		; potmeter state (0...1023)
;* Clock : ?
;**************************************************************************
read_potmeter	AD_GET	AD_POTMETER
		movf	ADRESH,w
		movwf	potmeter16
		bank1
		ERRORLEVEL -302
		movf	ADRESL,w
		ERRORLEVEL +302
		bank0
		movwf	potmeter16+1

rp_end		return




;***** calc_alpha *********************************************************
;* Calculate trigger delay time (in RE)
;* Input : alphamin16			; min. alpha in RE
;*	   alphamax16			; max. alpha in RE
;*	   potmeter16			; potmeter state (0...1023)
;* Output: alpha16			; wished trigger delay time in RE
;*	   alpha_ramp16			; real trigger delay time
;* Clock : ?
;**************************************************************************
calc_alpha
		MOV16	AARG16, alphamax16
		SUB16	AARG16, alphamin16		; AARG16 = (alphamax16 - alphamin16)
		
		MOV16	BARG16, potmeter16		; BARG16 = potmeter16

		MUL16					; AARG32 = (alphamax16 - alphamin16) * potmeter16

		MOV8	AARGB0, AARGB1			; AARG16 = (alphamax16 - alphamin16) * potmeter16 / 256
		MOV8	AARGB1, AARGB2
		
		SHR16	AARG16				; AARG16 = (alphamax16 - alphamin16) * potmeter16 / 1024
		SHR16	AARG16		

		ADD16	AARG16, alphamin16		; AARG16 = ((alphamax16 - alphamin16) * potmeter16 / 1024) + alphamin16

		MOV16	alpha16, AARG16			; alpha16 = ((alphamax16 - alphamin16) * potmeter16 / 1024) + alphamin16

	; -----------------------------------------------------------------

		CMP16	alpha16, alpha_ramp16
		JE	ca_end
		JB	ca_decrement
		goto	ca_increment

	; ------ decrement alpha ramp -------------------------------------

ca_decrement	SUBC16	alpha_ramp16, CONST_RAMP_SLOPE

		CMP16	alpha16, alpha_ramp16
		JNA	ca_end
		MOV16	alpha_ramp16, alpha16

		CMPC16	alpha_ramp16, (CONST_AVR_ALPHA-1000)
		JA	ca_end
		bcf	FLAG_BIGSETUPTIME

		goto ca_end

	; ------ increment alpha ramp -------------------------------------

ca_increment	ADDC16	alpha_ramp16, CONST_RAMP_SLOPE

		CMP16	alpha16, alpha_ramp16
		JNB	ca_end
		MOV16	alpha_ramp16, alpha16

		CMPC16	alpha_ramp16, (CONST_AVR_ALPHA+1000)
		JB	ca_end
		bsf	FLAG_BIGSETUPTIME

		goto ca_end

	; -----------------------------------------------------------------

ca_end		return



;***** calc_hold **********************************************************
;* Calculate trigger hold time (in RE)
;* Input : alpha_ramp16			; trigger delay time (alphamin16 ... alphamax16)
;*	   alphamin16			; min. alpha in RE
;*	   alphamax16			; max. alpha in RE
;* Output: hold16			; trigger hold time in RE
;* Clock : 18
;**************************************************************************
calc_hold
		MOV16	hold16, alphamax16
		SUB16	hold16, alpha_ramp16	
		ADDC16	hold16, CONST_MIN_HOLDTIME	; hold16 = alphamax16 - alpha_ramp16 + CONST_MIN_HOLDTIME

		return



;***** INCLUDES ***********************************************************

	include "..\..\..\modules\tmrx.inc"
	include "..\..\..\modules\math.inc"
	include "..\..\..\modules\adc.inc"
	include "..\..\..\modules\wait.inc"


;**************************************************************************
	end				  ; end of program








