;;==============================================================;;
;;			hand clock with fast and stop mode					;;
;;==============================================================;;
;;																;;
;; Program:         Hclock -- Hand clock module					;;
;; Code:            Jindra Fucik								;;
;; Platform:        Microchip PIC12F629, 32768 Hz				;;
;; Date:            04.06.2013									;;
;; First release:   04.06.2013									;;
;; LastDate:        07.08.2016									;;
;;																;;
;;==============================================================;;

; Minimal external components, uses external xtall at 32768 Hz 
; (reused from clock movement)

; This program is distributed as is but WITHOUT ANY WARRANTY
; I hope you enjoy!!
;
; Revisions:
; 04.06.2013	Start of writting code
; 07.08.2016	Changed switch usage

; ----- Definitions

#define		__VERNUM	D'02'
#define		__VERDAY	0x07
#define		__VERMONTH	0x08
#define		__VERYEAR	0x16

	LIST	   p=12F629	; target processor

	; errorlevel -305 ; Using default destination of 1 (file).
	errorlevel -302 ; Register in operand not in bank 0. Ensure that bank bits are correct.

	#include p12F629.inc

	__CONFIG  _BODEN_OFF & _CP_OFF & _WDT_OFF & _MCLRE_OFF & _PWRTE_ON & _LP_OSC 

	; Make sure that internal osc. is calibrated (although not used)
	; Value has to be read before reprogramming the device.

; Hardware
;                        +-----------+
;                   +3V -|Vdd  U  Vss|- GND
; |-68-100pf+32768xtall -|OSC1    GP0|- Speed1
; |-68-100pf+32768xtall -|OSC2    GP1|- Out1 -51R--+mot--|<--| 1N5819
;    o-pull-up---Speed2 -|GP3     GP2|- Out2 -51R--+mot--|<--| 1N5819
;                        +-----------+
; 68-100pF for LP osc (less than 37kHz)
; Speed1 & Speed2 are switches connected to ground, pull up to Vdd

; --- Macros
#define		DNOP		goto	$+1

; --- Constant values 

FXTAL		equ	D'32768'

GP_TRIS         equ     0x09			; GP0,GP3: inputs
GP_INI          equ     0x00			; all zero
OPTION_INI	equ	b'00001000'			; Option register: pull-up, falling GP2, Timer0 no prescaler 1:1
; Timer0 no prescaller mean fosc/4 = 32768 / 4 = 8192 Hz
WPU_INI		equ	0x01			; Weak pull-up enable for GP0. 

INTC_INI	equ	0x00			; disable interrupts
PIE1_INI	equ	0x00			; no interrupts


#define		SW_SPD1	GPIO,0			; switch to fast mode 1
#define		OUT_A	GPIO,1			; motor out A
#define		OUT_B	GPIO,2			; motor out 2
#define		SW_SPD2	GPIO,3			; switch to fast mode 2 (GPIO,3 only input)

; Fast mode table:
; Speed1 | Speed2 | Clock rate
; Off(H) | Off(H) | 1:1 = normal clock = 8192/256 = 32 ticks
; On (L) | Off(H) | 1:4 = 4x faster than normal; defined in EEPROM 1st position 32/4 = 8
; Off(H) | On (L) | 1:5.33 = 5.33x faster than normal; defined in EEPROM 2nf position 32/5.33 = 6
; Off(H) | Off(H) | 1:6.4 = 6.4x faster than normal; defined in EEPROM 3rd position 32/6.4 = 5

; Define the amount of time that the coil should
; be energised for a 'tick'.  This should be as low as 
; possible but varies between clock modules...
#define		ENERGISE_TIME	0x50


; --- EEPROM Section

#define		EE_INI		0x00

	cblock  EE_INI
EE_FCLK1			; Fast clock 1st divider
EE_FCLK2			; Fast clock 2nd divider
EE_FCLK3			; Fast clock 3rd divider
	endc


; ----- Variables

; --- Internal RAM Section

#define		RAMINI0		0x020		; 64 bytes
	cblock  RAMINI0
FCLK1				; Fast clock 1st divider
FCLK2				; Fast clock 2nd divider
FCLK3				; Fast clock 3rd divider
CLKCNT				; Counter for clock ticks (8192/256)
POLARITY			; next pulse polarity
ECNT				; pulse length counter
	endc



; --------------- Program Section --------------------------------------


		org	0x000

PowerUp:
		clrf	STATUS			; Bank 0 default
		clrf	INTCON			; Disable all interrupts
		clrf	PCLATH			; tables on page 0
		goto	INIT

; ----------------------------------------------------------------------

		org	0x004

Interrupt:
		;movwf	INT_W			; save context registers		;1
		;swapf	STATUS,w							;2
		;movwf	INT_STAT							;3
		;clrf	STATUS			; interrupt uses bank 0			;4

EndInt:
		;swapf	INT_STAT,w		; restore context registers	;49	;34
		;movwf	STATUS							;50	;35
		;swapf	INT_W,f							;51	;36
		;swapf	INT_W,w							;52	;37
		;retfie								;53,54	;38,39

;**********************************************************************************************************************
; Tables on first 256 bytes
;**********************************************************************************************************************
;
SpeedTable
	andlw	0x03
	addwf	PCL,f
	goto	NormalTime
	goto	FastClk1
	goto	FastClk2
	goto	FastClk3
	
;
	if ($ > d'255') 
		ERROR "  Tables exceded page 0.   If it works, why do you change it?   "
	endif
;

; ----------------------------------------------------------------------

INIT:
		clrf	GPIO
		movlw	0x07
		movwf	CMCON			; set GP2:0 to digital I/O

		bsf	STATUS,RP0		; bank 1
		movlw	GP_TRIS
		movwf	TRISIO
		;call	0x3FF			; get OSCCAL value
		;movwf	OSCCAL
		movlw	WPU_INI			; pull-ups
		movwf	WPU
		clrf	IOC			; interrupt on change
		clrf	VRCON			; voltage reference off
		movlw	OPTION_INI		; Option register: no pull-up, falling GP2, no prescaler, wdt 1:1
		movwf	OPTION_REG
		movlw	PIE1_INI
		movwf	PIE1
		bcf	STATUS,RP0		; bank 0
		clrf	PIR1
		movlw	0x00			; Timer 1 off, 1:1
		movwf	T1CON

		movlw	0x20			; clear RAM
		movwf	FSR
ClearRAM:
		clrf	INDF
		incf	FSR,f
		movlw	0x60
		xorwf	FSR,w
		btfss	STATUS,Z
		goto	ClearRAM

		movlw	INTC_INI
		movwf	INTCON			; disable all interrupts

		movlw	EE_FCLK1			; read saved FCLK1 value
		call	EE_Read
		movwf	FCLK1			
		movlw	EE_FCLK2			; read saved FCLK2 value
		call	EE_Read
		movwf	FCLK2			
		movlw	EE_FCLK3			; read saved FCLK3 value
		call	EE_Read
		movwf	FCLK3			
		clrf	TMR0
		clrf	CLKCNT

; ----------------------------------------------------------------------

MainLoop:
	btfss	INTCON,T0IF			; wait for next tick
	goto	MainLoop

	bcf		INTCON,T0IF
	incf	CLKCNT,f			; increment ticks

	movlw	0x00				; clear WREG
	btfss	SW_SPD1				; if SW_SPD1 switch is on,
	addlw	0x01				; add bit 1 to WREG
	btfss	SW_SPD2				; if SW_SPD2 switch is on,
	addlw	0x02				; add bit 2 to WREG
	
	goto	SpeedTable			; speed table will go to proper speed destination
	
FastClk1:
	movf	CLKCNT,w
	subwf	FCLK1,w
	btfss	STATUS,Z			; if FCLK1 is equal CLKCNT, send pulse
	btfss	STATUS,C			; if FCLK1 is Greater, do nothing
	goto	SendPulse			; else send pulse
	goto	MainLoop			

FastClk2:
	movf	CLKCNT,w
	subwf	FCLK2,w
	btfss	STATUS,Z			; if FCLK2 is equal CLKCNT, send pulse
	btfss	STATUS,C			; if FCLK2 is Greater, do nothing
	goto	SendPulse			; else send pulse
	goto	MainLoop			

FastClk3:
	movf	CLKCNT,w
	subwf	FCLK3,w
	btfss	STATUS,Z			; if FCLK3 is equal CLKCNT, send pulse
	btfss	STATUS,C			; if FCLK3 is Greater, do nothing
	goto	SendPulse			; else send pulse
	goto	MainLoop			


NormalTime:
	movf	CLKCNT,w
	andlw	0xE0 				; bits 7,6,5
	btfsc	STATUS,Z			; if CLKCNT>=32
	goto	MainLoop


SendPulse:
	incf	POLARITY,f
	clrf	CLKCNT

	btfss	POLARITY,0
	goto	SendPulseB

SendPulseA:
	bsf		OUT_A
	goto	SendPulseE

SendPulseB:
	bsf		OUT_B
	;goto	SendPulseE

SendPulseE:
	movlw	ENERGISE_TIME
	movwf	ECNT
SendPulseLoop:
	decfsz	ECNT,f
	goto	SendPulseLoop
	bcf		OUT_A
	bcf		OUT_B
	goto	MainLoop

;---------------------------------------------------------------------------

EE_Read:
		bsf	STATUS,RP0		; w=ADR
		movwf	EEADR
		bsf	EECON1,RD
		movf	EEDATA,w
		bcf	STATUS,RP0
		return


; ----- EEPROM default values


		org	0x2100

; TMR0 = clock / 4 = 32768 / 4 = 8192
; TMR0 over = 256 ~ 8192 / 256 = 32
; 32 times TMR0 over = 1 sec
; 8 times TMR0 = 4x faster
; 6 times TMR0 =5.333x normal clock
; 5 times TMR0 =6.4x normal clock
		dw	0x08			; EE_FCLK1	fast clock counter - 5=6.4x normal clock 6=5.333x normal clock
		dw	0x06			; EE_FCLK2	fast clock counter - 5=6.4x normal clock 6=5.333x normal clock
		dw	0x05			; EE_FCLK3	fast clock counter - 5=6.4x normal clock 6=5.333x normal clock

		org	0x2120

		dt	"FastClck"
		dt	" ver. ",(__VERNUM   & 0x0F)+0x30," "
		dt	"J.Fucik "
		dt	(__VERDAY   >> 4)  +0x30
		dt	(__VERDAY   & 0x0F)+0x30,"/"
		dt	(__VERMONTH >> 4)  +0x30
		dt	(__VERMONTH & 0x0F)+0x30,"/"
		dt	(__VERYEAR  >> 4)  +0x30
		dt	(__VERYEAR  & 0x0F)+0x30

	end