;********************************************************************
 ;       This is a dimmer based on application note
 ;       using a Z86E04 MCU running on CCP
 ;       This program is assembled only by ZiLOG ZASM assembler
 ;********************************************************************
 ;
 ;********************************************************************
 ;       Quando e' desiderato una partenza lenta impostare l'equ 
 ;       SOFTSTART_WISHED to 1
 ;********************************************************************
SOFTSTART_WISHED .equ    0       ; 1 = Yes     0 = No

 ;********************************************************************
 ;       Bit number definitions
 ;********************************************************************
bitno0          .equ    %01
bitno1          .equ    %02
bitno2          .equ    %04
bitno3          .equ    %08
bitno4          .equ    %10
bitno5          .equ    %20
bitno6          .equ    %40
bitno7          .equ    %80
 ;********************************************************************
 ;               PORTS DEFINITION
 ;********************************************************************
 ;       Port 2 pin
 ;       P20 : output  for triac gate
.triac_gate     .equ    bitno0 
 ;       P21-P27 : output idle N.C.
 ;       Port 0 pin
 ;       P00 : power. UP key 
.upkey          .equ    bitno0          
 ;       P01 : power. DOWN key 
.downkey        .equ    bitno1          
 ;       P02 : idle input
 ;       Port 3 pin
 ;       P31 : idle input, pull to ground
 ;       P32 : AC zero crossing detection 
.acinput        .equ    bitno2
 ;       P33 : Voltage reference = GND 
 ;********************************************************************
 ;               REGISTERS DEFINITION
 ;********************************************************************
power_level      .equ    @rr4           ; phase table add. of actual power level
power_levelHB    .equ    r4             ; address offset HB for phase table
power_levelLB    .equ    r5             ; address offset LB (lower nibble = 						; power level value)                                                        
dimmerflags      .equ    r6             ; register used by the dimmer
					; routines
period_count .equ    r7                 ; counts the numbers of periods
shadow           .equ    r8             ; general purpose shadow
 ;softstartcounter .set    r9           ; counts time for softstart 
delay_counter    .equ    %FE            ; counter for delay routine 
 ; 
 ;********************************************************************
 ;               BITS DEFINITION
 ;********************************************************************
old_ac_level     .equ    bitno0
new_ac_level     .equ    bitno1
is_ignition_on?  .equ    bitno2
positive_part    .equ    bitno3
 ;
 ;********************************************************************
 ;               CONSTANTS DEFINITION
 ;********************************************************************
fifty_Hz         .equ    11110010b       ; prescaler1=60 single shot
sixty_Hz         .equ    11001010b       ; prescaler1=50 single shot
start_up_power   .equ    %f7             ; power start level <= (15+%f0)
maxpower         .equ    %f9             ; maximum power <= (15+%f0)
minpower         .equ    %f1             ; minimum power >= (0+%f0)
T_to_2ignition   .equ    156             ; time between 1st and 2nd ignition
zcforskey        .equ    20              ; scankey on every xth zero crossing
softstart_time   .equ    20              ; softstart takes x * 20 millisec.
ignition_time    .equ     3              ; ignition on for app. 150Ęsec.
 ;
 ;********************************************************************
 ;               MACROS
 ;       Refer to Z8 technical manual for macro definition
 ;********************************************************************
bset:           .macro  arg1,arg2
		or      arg1,#arg2
		.endm
bclr:           .macro  arg3,arg4
		and     arg3,#^c (arg4) ^& 0ffh
		.endm
brset:          .macro  arg1,arg2,arg3
		tm      arg1,#arg2
		jr      nz,arg3
		.endm
brclr:          .macro  arg1,arg2,arg3
		tm      arg1,#arg2
		jr      z,arg3
		.endm
release_ignition: .macro
		bset    p2,.triac_gate
		.endm
ignite_triac:   .macro
		bclr    p2,.triac_gate
		.endm
start_T1:       .macro
		ld      tmr,#00001100b
		.endm
 ;********************************************************************
 ;               INTERRUPTS VECTOR
 ;********************************************************************
		.mlist  on
		.list   on
 ;       Interrupt vector address  %00 to %0C
		.ORG    %0000
 ;********************************************************************
 ;               solo per l'emulatore CCP
 ;********************************************************************
 ;                .word   comparator2    ; for emulation only 
 ;                .word   irq1           ; for emulation only
 ;                .word   irq2           ; for emulation only
 ;                .word   irq3           ; for emulation only
 ;                .word   irq4           ; for emulation only
 ;                .word   timer1         ; for emulation only
 ;********************************************************************
 ;               solo per programmazione OTPs
 ;********************************************************************
		.word   irq0 
		.word   irq1
		.word   irq2
		.word   comparator2
		.word   irq4
		.word   timer1
 ;************************************************
 ;               PROGRAM STARTS HERE             *
 ;************************************************
BEGINNING:      
		.ORG    %0C 
irq0:
irq1:
irq2:
irq3:
irq4:
		di
		ld      P01M,#00000101b 
					       ;P0, P1 input, internal stack
		ld      P2M,#00000000b         
					       ;P20-P27 output
		ld      P3M,#00000011b              
					       ;P3 analog + P2 push pull
		or      P2,#00000001b          ;Switchoff the triac

		clr     SPH
		ld      SPL,#%40               ;INIT STACK POINTER
 ;********************************************************************
 ;               FOR EMULATION
 ;********************************************************************
 ;                ld      IPR,#00011100b         ; for emulation only
 ;                ld      IMR,#00100100b         ; for emulation only
 ;                ld      IRQ,#01000000b         ; for emulation only
 ;********************************************************************
 ;               FOR BURNING OTPs
 ;********************************************************************
		ld      IPR,#00101010b         ; IRQ3 > IRQ5
		ld      IMR,#00101000b         ; enable T1 interrupt
					       ; + Comparator2  
					       ; (rising edge) interrupt
 ; INITIALIZE RAM TO "0"
		srp     #%30
		ld      R14,#%3d
ZRAM:           clr     @R14
		djnz    R14,ZRAM
 ;       Initialize all registers
		srp     #%00                    ; set working register to %00
		call    delay40mS               ; wait for AC to be stable
		ld      power_levelHB,#%01      ; offset for phase table add.
		ld      pre1,#fifty_Hz          ; T1 preset for 50H
		.IF     SOFTSTART_WISHED
		ld      power_levelLB,#minpower ; preset power level
		ei
		call    softstart               ; increase power slowly 
		.ELSE
		ld      power_levelLB,#start_up_power                                 
		ei
		.ENDIF
 ;********************************************************************
 ; 
 ;********************************************************************
 ;       MAIN USER PROGRAM
 ;       The dimmer runs as a batch task via T1 + C2 interrupt.
 ;       This is the user program that runs in front. 
 ;********************************************************************
Main:
		NOP                      
		jr Main
 ;********************************************************************
 ;              SUBROUTINES
 ;********************************************************************
		call 	delay40mS:
		call    delay10mS
		call    delay10mS
		call    delay10mS
		call    delay10mS
		ret


;       1.5uS x  (30x222)  =  10 mS

delay10mS:
		ld      delay_counter,#222      ; 6 cycles
loop1:
		nop                             ; 6 cycles
		nop                             ; 6 cycles
		dec     delay_counter           ; 6 cycles
		jr      nz,loop1                ; 12 cycles
		ret


;               Increase power slowly after the start
;               for long light bulb life.
   
softstart:
		 .IF              SOFTSTART_WISHED    
softstartcounter .set    r5                             ; counts time for softstart 
		 cp      power_levelLB,#start_up_power  ; if power level is
		 jr      GE,end_softstart               ; below start level 
softstart_delay:                 
		 ld      softstartcounter,#softstart_time    
		 call    delay10mS                      ; then increase power   
		 djnz    softstartcounter,softstart_delay ; every x millisec.
		 inc     power_levelLB                      
		 jr      softstart                      
end_softstart:
		 ret
		 .ENDIF

                Scan key in every 20th period
;               ie 20mS x 20   = 400mS for 50Hz AC
;                  16.7mS x 20 = 334mS for 60Hz AC
  
scankey:
		djnz    period_count,end_scankey       ; check keys on every
						       ; 20th period
		ld      period_count,#zcforskey
		brset   P0,.upkey,increase_power       ; check increment key
		brset   P0,.downkey,decrease_power     ; check decrement key
		jr      end_scankey


;       Increment the output power if UP key is pressed
;       Maximum level = 15
   
increase_power:
		inc     power_levelLB
		cp      power_levelLB,#maxpower       ; if the power level
		jr      LE,end_scankey                ; is too high, then
		ld      power_levelLB,#maxpower       ; keep at max. power
		jr      end_scankey



;       Decrement the output power if DOWN key is pressed
;       Minimum level = 0
  
decrease_power:
		dec     power_levelLB
		cp      power_levelLB,#minpower      ; if the power level
		jr      GE,end_scankey               ; is too low, then
		ld      power_levelLB,#minpower      ; keep at min. power

end_scankey:
		ret



;       Whenever a zero crossing from negative to positive occurs, means
;       the AC period starts, a comparator2 interrupt is serviced. 
;       AC line change in every 10mS for 50Hz, 8.3mS for 60Hz
comparator2:	; ac had a negative to positive
		push    rp                   ; zero crossing
		srp     #%00
		ldc     shadow,power_level
		ld      T1,shadow            ; let T1 run till phase angle 
		start_T1                     ; for 1st ignition is reached
		bset    dimmerflags,positive_part
		pop     rp                   ; positive part of
		iret                         ; ac period 


;       Timer1 interrupt occurs 4 times during one ac period.
;       2 times to ignite the triac and two times to release the ignition
;       again.

timer1:
		push    rp                              ; working register
		srp     #%00                            ; group 0 reserved
							; for timer1
							; interrupt 
						     
		brset   dimmerflags,is_ignition_on?,turn_off_ignition
		
turn_on_ignition:                
		ignite_triac                            ; ignite the triac
		ld      T1,#ignition_time               ; let T1 run for the
		start_T1                                ; ignition time
		bset    dimmerflags,is_ignition_on?
		jr      end_of_interrupt

turn_off_ignition: 
		release_ignition
		bclr    dimmerflags,is_ignition_on?
		brclr   dimmerflags,positive_part,end_of_interrupt
		ld      T1,#T_to_2ignition              ; let T1 run for
		start_T1                                ; 10 or 8.3 milli
		call    scankey                         ; seconds
		bclr    dimmerflags,positive_part

end_of_interrupt:
		pop     rp
		iret



 ;       Currently no more than 16 values are possible in
 ;       the phase table without other changes to the program.

		.org    %1f0
phase_table:
		.byte   145             ; zero power
		.byte   124             ; 1/10 power
		.byte   111             ; 2/10 power
		.byte   101             ; 3/10 power
		.byte    92             ; 4/10 power
		.byte    83             ; 5/10 power
		.byte    75             ; 6/10 power
		.byte    66             ; 7/10 power
		.byte    56             ; 8/10 power
		.byte    43             ; 9/10 power
		.byte    07             ; full power

		.end