;******************************************************
;******************************************************
;
; Main Project     : FT301D
; Project Name     : FT301D - Replacement Digital Display
; File Name        : hardware.asm
; Version          : A03
; PIC Used         : PIC16F887
; Assembler        : MPLAB MPASMWIN from Microchip Technology, Inc.
; Initial Date     : May 1, 2011
; Last Update date : May 1, 2011
; Firmware Eng.    : WA7ZVY
; HW Design Eng.   : WA7ZVY
;
;******************************************************
;
; These routines deal with hardware specific details.
;
;	1) Initializing the hardware
;	3) Processing Timer 1 interrupts
;
;******************************************************
;
; 	Function List (in top-2-bottom order):
;		void init_hardware(void);
;		void timer1_irq_service(void);
;
;******************************************************
;
;   Modification History:
;   =-=-=-=-=-=-=-=-=-=-=
;   20110501 pm - Initial creation.
;
;*****************************************************
;   === Include files ===
;*****************************************************
 	LIST   P=16F887			;List directive to define processor

#include	P16F887.INC			;Processor specific variable definitions
#include	constants.inc		;Coding constants
#include	micro_bits.inc		;Hardware defined bits
#include	variable_def.inc	;Variable definitions


HARDWARE_CODE	CODE				;hardware code space

;*****************************************************
;*****************************************************
;
;	Name:		init_hardware
;	
;	Abstract:
;	This is the cold start FT301D hardware initialization
;	code. It is called by main as the first thing. The
;	presumption is that this code is executed whenever
;	the FT301D microcontroller is released from reset.
;
;	Callable Routines:
		global	init_hardware
;
;	Called Routines:  None.
;
;	Global Variables Used:  None.
;		
;	Local Variables Used:  None.
;	
;	Return Values:	None.
;		
;*****************************************************
;*****************************************************
init_hardware
	banksel	BANK0
	movlw	0x00			;Turn off ALL of the various interrupts, should be done by
	movwf	INTCON			; reset, but just do it to be sure
	banksel	BANK1
	movwf	PIE1
	movwf	PIE2
	bsf		OSCCON,IRCF0	;Bump up procssor speed to 8MHz (default for internal clock is 4MHz)

; Initialize the I/O pins
	banksel	BANK0
	movlw	CFG_PORTA		;Set the state of the pins
	movwf	PORTA
	movlw	CFG_PORTB
	movwf	PORTB
	movlw	CFG_PORTC
	movwf	PORTC
	movlw	CFG_PORTD
	movwf	PORTD
	movlw	CFG_PORTE
	movlw	PORTE

	banksel	BANK1
	movlw	CFG_TRISA		;Set the direction of the pins
	movwf	TRISA
	movlw	CFG_TRISB
	movwf	TRISB
	movlw	CFG_TRISC
	movwf	TRISC
	movlw	CFG_TRISD
	movwf	TRISD
	movlw	CFG_TRISE
	movwf	TRISE

	banksel	BANK3
	movlw	CFG_ANSELH		;Turn off analog mode on pin RB5 so it reads digital
	movwf	ANSELH

	banksel BANK2
	movlw	CFG_CM2CON1		;Set Timer 1 function to count the gated frequency
	banksel	BANK0
	movlw	CFG_T1CON
	movwf	T1CON

; Initialize Timer 2 registers to generate an interrupt for multiplexing the digits
	banksel	BANK1
	movlw	0xff
	movwf	PR2				;Timer 2 period register
	banksel	BANK0
	movlw	0x00
	movwf	TMR2			;Timer 2 counter
	movlw	CFG_T2CON
	movwf	T2CON			;Timer 2 pre and post scalers and turn on Timer 2

; Clear any interrupt flags
	bcf		PIR1,TMR1IF
	nop
	bcf		PIR1,TMR2IF

	return




;*****************************************************
;*****************************************************
;
;	Name:		timer1_irq_service
;	
;	Abstract:
;	This routine services the timer 1 interrupts.
;
;	Timer 1:
;	a). Used for Frequency Counting. The Timer 1 is set to generate
;		an interrupt whenever the Timer's counter rolls over from
;       0xFFFF to 0x0000.  Upon a roll-over, the more significant
;       count value is incremented.  This counting continues as long
;       as the gate signal, /T1G (RB5), is active.
;
;	Callable Routines:
		global	timer1_irq_service
;
;	Called Routines:  None.
;		
;	Global Variables Used:
;		b0_counter2
;		b0_counter3
;
;	Local Variables:  None.
;	
;	Return Values:	None.
;		
;*****************************************************
;*****************************************************
timer1_irq_service
	banksel	BANK0
	btfss	PIR1,TMR1IF			;check for an interrupt pending
	return						;no interrupt, so just return
	incfsz	b0_counter2,F		;increment the high order counters
	decf	b0_counter3,F
	nop
	incf	b0_counter3,F

; Clear interrupt flag
	bcf		PIR1,TMR1IF

	return



;*****************************************************
;*****************************************************
;
;	Name:		timer2_irq_service
;	
;	Abstract:
;	This routine services the timer 2 interrupts.
;
;	Timer 2:
;	a). Used to time the multiplexing of the LED digits.
;		Mux'ing digits at 2msec per gives an
;		approximate 60Hz overall refresh rate.
;
;	Callable Routines:
		global	timer2_irq_service
;
;	Called Routines:  None.
;		
;	Global Variables Used:
;		b0_digit_select
;		b0_digit0_segments
;		b0_digit1_segments
;		b0_digit2_segments
;		b0_digit3_segments
;		b0_digit4_segments
;		b0_digit5_segments
;
;	Local Variables:  None.
;	
;	Return Values:	None.
;		
;*****************************************************
;*****************************************************
timer2_irq_service
	banksel	BANK0
	btfss	PIR1,TMR2IF			;check for an interrupt pending
	return						;no interrupt, so just return

	movlw	0x0f				;turn off any currently lit digit
	movwf	PORTE
	movwf	PORTC

	movlw	0x07				;mask off the lower 3 bits of the digit select counter
	andwf	b0_digit_select,F

	movlw	0x00				;check if this is the digit to illuminate
	xorwf	b0_digit_select,W
	btfss	STATUS,Z
	goto	t2is_1				;its not time for this digit, so try the next one
	movf	b0_digit0_segments,W
	andlw	PORTA_SEGMENT_MASK
	movwf	PORTA
	movf	b0_digit0_segments,W
	andlw	PORTB_SEGMENT_MASK
	movwf	PORTB
	movlw	HUNDREDS_OF_HZ
	movwf	PORTE				;turn on digit
	goto	t2is_exit

t2is_1
	movlw	0x01				;check if this is the digit to illuminate
	xorwf	b0_digit_select,W
	btfss	STATUS,Z
	goto	t2is_2				;its not time for this digit, so try the next one
	movf	b0_digit1_segments,W
	andlw	PORTA_SEGMENT_MASK
	movwf	PORTA
	movf	b0_digit1_segments,W
	andlw	PORTB_SEGMENT_MASK
	movwf	PORTB
	movlw	ONES_OF_KHZ
	movwf	PORTE				;turn on digit
	goto	t2is_exit

t2is_2
	movlw	0x02				;check if this is the digit to illuminate
	xorwf	b0_digit_select,W
	btfss	STATUS,Z
	goto	t2is_3				;its not time for this digit, so try the next one
	movf	b0_digit2_segments,W
	andlw	PORTA_SEGMENT_MASK
	movwf	PORTA
	movf	b0_digit2_segments,W
	andlw	PORTB_SEGMENT_MASK
	movwf	PORTB
	movlw	TENS_OF_KHZ
	movwf	PORTE				;turn on digit
	goto	t2is_exit

t2is_3
	movlw	0x03				;check if this is the digit to illuminate
	xorwf	b0_digit_select,W
	btfss	STATUS,Z
	goto	t2is_4				;its not time for this digit, so try the next one
	movf	b0_digit3_segments,W
	andlw	PORTA_SEGMENT_MASK
	movwf	PORTA
	movf	b0_digit3_segments,W
	andlw	PORTB_SEGMENT_MASK
	movwf	PORTB
	movlw	HUNDREDS_OF_KHZ
	movwf	PORTC				;turn on digit
	goto	t2is_exit

t2is_4
	movlw	0x04				;check if this is the digit to illuminate
	xorwf	b0_digit_select,W
	btfss	STATUS,Z
	goto	t2is_5				;its not time for this digit, so try the next one
	movf	b0_digit4_segments,W
	andlw	PORTA_SEGMENT_MASK
	movwf	PORTA
	movf	b0_digit4_segments,W
	andlw	PORTB_SEGMENT_MASK
	movwf	PORTB
	movlw	ONES_OF_MHZ
	movwf	PORTC				;turn on digit
	goto	t2is_exit

t2is_5
	movlw	0x05				;check if this is the digit to illuminate
	xorwf	b0_digit_select,W
	btfss	STATUS,Z
	goto	t2is_6				;its not time for this digit, so try the next one
	movf	b0_digit5_segments,W
	andlw	PORTA_SEGMENT_MASK
	movwf	PORTA
	movf	b0_digit5_segments,W
	andlw	PORTB_SEGMENT_MASK
	movwf	PORTB
	movlw	TENS_OF_MHZ
	movwf	PORTC				;turn on digit
	goto	t2is_exit

t2is_6

t2is_exit
	incf	b0_digit_select,F

; Clear interrupt flag
	banksel	BANK0
	bcf		PIR1,TMR2IF

	return



;*****************************************************
;*****************************************************
;
;	Name:		convert_to_segments
;	
;	Abstract:
;	This routine converts the ASCII value in the digit
;	memories to LED digit segments to light up.
;
;	Callable Routines:
		global	convert_to_segments
;
;	Called Routines:
		extern	segment_table
;		
;	Global Variables Used:  b0_digit0, b0_digit0_segments
;							b0_digit1, b0_digit1_segments
;							b0_digit2, b0_digit2_segments
;							b0_digit3, b0_digit3_segments
;							b0_digit4, b0_digit4_segments
;							b0_digit5, b0_digit5_segments
;
;	Local Variables:  None.
;	
;	Return Values:	None.
;		
;*****************************************************
;*****************************************************
convert_to_segments
	banksel	BANK0
	btfss	b0_error_flags,0
	goto	cts_0
	movlw	B'00111111'			;turn on all of the decimal points if there is an error
	movwf	b0_dpoint_flags

cts_0
	movlw	0x20				;for digit 0
	subwf	b0_digit0,W
	pagesel	segment_table
	call	segment_table		;on return W contains the segments
	movwf	b0_digit0_segments
	btfss	b0_dpoint_flags,0	;check to see if this decimal point should be on
	goto	cts_1
	movlw	DP_SEG
	iorwf	b0_digit0_segments,F

cts_1
	movlw	0x20				;for digit 1
	subwf	b0_digit1,W
	call	segment_table		;on return W contains the segments
	movwf	b0_digit1_segments
	btfss	b0_dpoint_flags,1	;check to see if this decimal point should be on
	goto	cts_2
	movlw	DP_SEG
	iorwf	b0_digit1_segments,F

cts_2
	movlw	0x20				;for digit 2
	subwf	b0_digit2,W
	call	segment_table		;on return W contains the segments
	movwf	b0_digit2_segments
	btfss	b0_dpoint_flags,2	;check to see if this decimal point should be on
	goto	cts_3
	movlw	DP_SEG
	iorwf	b0_digit2_segments,F

cts_3
	movlw	0x20				;for digit 3
	subwf	b0_digit3,W
	call	segment_table		;on return W contains the segments
	movwf	b0_digit3_segments
	btfss	b0_dpoint_flags,3	;check to see if this decimal point should be on
	goto	cts_4
	movlw	DP_SEG
	iorwf	b0_digit3_segments,F

cts_4
	movlw	0x20				;for digit 4
	subwf	b0_digit4,W
	call	segment_table		;on return W contains the segments
	movwf	b0_digit4_segments
	btfss	b0_dpoint_flags,4	;check to see if this decimal point should be on
	goto	cts_5
	movlw	DP_SEG
	iorwf	b0_digit4_segments,F

cts_5
	movlw	0x20				;for digit 5
	subwf	b0_digit5,W
	call	segment_table		;on return W contains the segments
	movwf	b0_digit5_segments
	btfss	b0_dpoint_flags,5	;check to see if this decimal point should be on
	goto	cts_6
	movlw	DP_SEG
	iorwf	b0_digit5_segments,F

cts_6
	return


	end
; End of File (hardware.asm)
