;**********************************************************************
; flashlight.asm
; Software for LED flashlight
; used as a step up converter to drive 12 white LEDs out of a 4,5V battery pack
; -regulated current (ca. 20mA)
; -overvoltage protction (LEDs failure)
; -undervoltage protection (Battery low)
;
; Usage of Pins:
; GP5: -
; GP4: input for overvoltage protection
; GP3: -
; GP2: output to driver transistor
; GP1: input for current sensing
; GP0: -
;
; Assuming INTOSC f=4MHz
;-------------------------------
;Stephan Asmus, Germany
;(c) info@sasmus.de
;
;-------------------------------
; 16.11.2019	Starting
; 17.11.2019  1st version running
; 
;**********************************************************************
    LIST   P=PIC12F675

    #include <p12f675.inc>	; processor specific variable definitions

    errorlevel  -302			;No bank select warnings

	__CONFIG _FOSC_INTRCIO & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _BOREN_ON & _CP_OFF & _CPD_OFF & 0x01ff

	;added & 0x01ff because of error within MPLAB X IDE Toolchain. / inc file for 12f675 

;***** VARIABLE DEFINITIONS
    cblock 0x20			;define a series of variables.
		W_TEMP			;context saving during interrupt
		STATUS_TEMP		;dto
		d1				;Register to hold Delayloop	
		d2				;dto.
		d3				;dto
		pulse_h			;current pulse length high
    endc
; ***********Constants definitions
#define output		GPIO,2	;output to power stage transistor
#define sense			CMCON,6	;current sensing result (1 if max current received)
#define overvoltage	GPIO,4	;over voltage input
; **********************************************************************
; **********************************************************************
    ORG		0x000		; processor reset vector
    goto		init			; go to beginning of program
    
	ORG		0x004		; interrupt vector location		
	movwf	W_TEMP
	swapf	STATUS,w
	bcf		STATUS,RP0
	movwf	STATUS_TEMP
	
	;the only interrupt is GP change on GP4, so we came here if an overvoltage was identified (GP4=1)
	movf		GPIO,w		;read GPIO to handle mismatch condition
	call		handle_ov		;handle over-voltage condition
	bcf		INTCON,GPIF	;clear interrupt flag
	
	swapf	STATUS_TEMP,w
	movwf	STATUS
	swapf	W_TEMP,f
	swapf	W_TEMP,w
	retfie				;
; ------------------------------------------------------------------------------
; START OF CODE to initialize the processor (Variables, I/O ...)
; ------------------------------------------------------------------------------
init
    bcf		STATUS,RP0		; Select Bank 0
    ;initialise variables & hardware
    clrf		GPIO				; Init I/O-Port by clearing the outp. latches.
	movlw	b'00010100'		;output inverted (since sense input is on VIN-) and internal vref w/o output
	movwf	CMCON			;

    bsf		STATUS, RP0		;Switch to BANK 1
	btfss	PCON,1			;if clear, a power-on Reset occurred
	goto		init1			;if power on reset, then no need to check brown out
	btfss	PCON,0			;check if Brown-out reset occurred
	call		delay1s			;if brown out then delay for additional 1sec
	bsf		PCON,0			;set to 1 (no BOR)
init1
	bsf		PCON,1			;set power on reset indicator to 1 to identify brown out later
	movlw	b'10100111'		;vref enabled, low range, vref=(7/24)*Vdd = 1,3125V at 4,5 V Vdd 
	movwf	VRCON
	movlw	b'00000010'		;configure analog input (GP1/AN1 analog, others digital)
	clrf		ANSEL			;
    movlw	b'00010010'		;configure in/output (GP1, GP4: input. others output)
    movwf	TRISIO			;
	movlw	b'00000000'		;no weak pullup
    movwf	WPU				;
	movlw	b'10001000'		;No Pullups, internal clock for timer 0, prescaler to WDT
    movwf	OPTION_REG		;
	movlw	b'00010000'		;interrupt on change on GP4
	movwf	IOC
	;calibrating the oscillator...
    call		3FFh 			;Get the cal value
    movwf	OSCCAL 			;Calibrate it

    bcf		STATUS, RP0		;Back to BANK 0
	clrf		INTCON			;no interrupts, clear all flags
	bsf		INTCON,GPIE		;enable GP interrupt on change
	bsf		INTCON,GIE		;enable global interrupts
	
	; init conditions
    movlw	0x01
	movwf	pulse_h			;Start with minimal pulse length
	clrf		TMR0				;clear timer 0
; ******************************************************************************
; MAIN, here we go...
; ******************************************************************************
startup
    bcf		output		;output off

mainloop
	;now we have to set TMR0 to "255-pulse_h"
	movf		pulse_h,w	;high phase
	sublw	0xff
	bcf		INTCON,T0IF
	movwf	TMR0
	;4
	bsf		output		;switch transistor on
	;now during the on state we have time to do things that have to be done ...
	;(overvoltage-protection moved to ISR)
	btfss	sense		;add to pulse lenght if < max current, otherwise decrement it 
	incf		pulse_h,f
	btfsc	sense
	decf		pulse_h,f
	;max loop = 60, max on: 90% =54. Because TMR0 is inhibited after a write for 2 cycles, we are reducing these values to 56 and 50
	movf		pulse_h,w
	xorlw	d'51'		;check if pulse_h is > max (50)
	btfsc	STATUS,Z
	decf		pulse_h,f	;yes, than set back to 50
	
	movf		pulse_h,w
	btfsc	STATUS,Z		;check if pulse_h is < min (1)
	bsf		pulse_h,0	;yes, than set to 1
	
	sublw	d'50'		;calculate duration of low phase (w still holds pulse_h) 
						;should be d56, 'cause outer loop holds some more instructions, we reduce the "off" loop with 6 to reduce the error
	sublw	0xff			;prepare next TRMR0-value...
	
	btfss	INTCON,T0IF	;now wait until TMR0 overflow
	goto		$-1

	;not relevant
	bcf		INTCON,T0IF
	movwf	TMR0			;prepare delay loop für low phase
	bcf		output		;begin low phase
	
	btfss	INTCON,T0IF
	goto		$-1
	;2
	goto		mainloop		;and start over
	;2
	;low phase is longer than necessary: 8 Tosc
	
handle_ov					;we went here if GP4 got high, which means, that the output-voltage exeeds the limits
	bcf		output		;first: shut off power stage
	movlw	0x01			;set pulse duration to min
	movwf	pulse_h
	call		delay1s		;and wait for a moment to cool things down....
	
	btfsc	overvoltage	;wait until no overvoltage detected
	goto		$-1			
	
	return		;and try again
; ------------------------------------------------------------------------------
; delay: several delay routines used in the program
; ------------------------------------------------------------------------------
delay1s
			;999990 cycles
    movlw	0x07
    movwf	d1
    movlw	0x2F
    movwf	d2
    movlw	0x03
    movwf	d3
delay1s_0
    decfsz	d1, f
    goto	$+2
    decfsz	d2, f
    goto	$+2
    decfsz	d3, f
    goto		delay1s_0
			;6 cycles
    goto	$+1
    goto	$+1
    goto	$+1
			;4 cycles (including call)
    return

    END					;'end of program''









