view src/isr.asm @ 622:02d1386429a6

0x60 added for (future) option to change logbook offset via PC/Bluetooth
author heinrichsweikamp
date Wed, 10 Apr 2019 10:51:07 +0200
parents 1ad0531e9078
children c40025d8e750
line wrap: on
line source

;=============================================================================
;
;   File isr.asm									REFACTORED VERSION V2.99f
;
;   INTERUPT subroutines
;
;   Copyright (c) 2011, JD Gascuel, HeinrichsWeikamp, all right reserved.
;=============================================================================
; HISTORY
;  2011-05-24 : [jDG] Cleanups from initial Matthias code.

#include "hwos.inc"
#include "shared_definitions.h"			; Mailbox from/to p2_deco.c
#include "ms5541.inc"
#include "adc_lightsensor.inc"
#include "eeprom_rs232.inc"

;=============================================================================

	extern	start

isr_high	CODE	0x0008				; high priority interrupts
	bra		HighInt
	nop
	nop
	nop
	nop
	nop
	nop
	bra		HighInt

isr_low		CODE	0x00018				; low priority interrupts
;	*** low priority interrupts not used
	retfie	FAST						; restores BSR, STATUS and WREG

HighInt:
	movff	PRODL,isr_prod+0
	movff	PRODH,isr_prod+1

	; Buttons
	btfsc	PIR1,TMR1IF					; timer 1 INT (button hold-down timer)
	rcall	timer1int
	btfsc	INTCON,INT0IF				; buttons
	rcall	isr_switch_right
	btfsc	INTCON3,INT1IF				; buttons
	rcall	isr_switch_left

	; IR/S8 link timer int
	btfsc	PIR3,RC2IF					; UART 2
	rcall	isr_uart2					; IR/S8 link
	btfsc	PIR2,TMR3IF					; timer 3
	rcall	isr_timer3					; IR-Link timeout

	; Pressure sensor and others
	btfsc	PIR5,TMR7IF					; timer 7
	rcall	isr_tmr7					; every 62.5ms

	; RTCC
	btfsc	PIR3,RTCCIF					; real-time-clock interrupt
	rcall	isr_rtcc					; may return in bank common!

	movff	isr_prod+1,PRODH
	movff	isr_prod+0,PRODL
	retfie	FAST						; restores BSR, STATUS and WREG

isr_set_speed_to_normal:
	; Set speed to normal
	movlw	b'01110010'
	movwf	OSCCON						; 16 MHz INTOSC
	movlw	b'00000000'
	movwf	OSCTUNE						; 4x PLL disable (bit 6) - only works with 8 or 16 MHz (=32 or 64 MHz)
	movlw	T2CON_NORMAL
	movwf	T2CON
	btfss	OSCCON,HFIOFS
	bra		$-2							; wait until clock is stable
	return

isr_dimm_tft:							; adjust until max_CCPR1L=CCPR1L
	banksel	common
	btfsc	tft_is_dimming				; ignore while dimming
	return
	banksel	isr_backup
	movf	max_CCPR1L,W
	cpfsgt	CCPR1L						; CCPR1L > max_CCPR1L ?
	bra		isr_dimm_tft2				; NO - dimm up
	; dimm down
	decf	CCPR1L,F					; -1
	return
isr_dimm_tft2:
	movf	max_CCPR1L,W
	sublw	ambient_light_min_eco
	cpfsgt	CCPR1L						; CCPR1L > max_CCPR1L-ambient_light_min_eco ?
	bra		isr_dimm_tft3				; NO - dimm up slow
	; dimm up faster
	movlw	.10
	addwf	CCPR1L,F
isr_dimm_tft3:
	incf	CCPR1L,F					; +1
	return
	nop
	nop									; block flash here

isr_restore	CODE	0x00080				; restore first flash page from EEPROM
restore_flash_0x00080:
	goto	restore_flash

isr_routines							; CODE
;=============================================================================

isr_uart2:								; IR/S8 link
	banksel	RCREG2
	movf	RCREG2,W
	bcf		RCSTA2,CREN					; clear receiver status
	bsf		RCSTA2,CREN
	banksel	isr_backup
	incf	ir_s8_counter,F				; increase counter
	movff	ir_s8_counter,isr1_temp		; copy
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.0
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.1
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.2
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.3
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.4
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.5
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.6
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.7
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.8
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.9
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.10
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.11
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.12
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.13
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.14
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.15
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.16
	dcfsnz	isr1_temp,F
	movwf	ir_s8_buffer+.17

	clrf	TMR3L						; preload timer
	movlw	.253
	movwf	TMR3H
	bsf		T3CON,TMR3ON				; (re)start timeout counter
	return

isr_timer3:								; IR/S8 link timeout
	bcf		T3CON,TMR3ON				; stop timer 3
	banksel	isr_backup					; select bank 0 for ISR data
	movlw	.15
	cpfseq	ir_s8_counter				; got exactly 15 bytes?
	bra		isr_timer3_1				; NO  - test for 16bytes
	bra		isr_timer3_ir				; YES - got 15 bytes, compute local checksum
isr_timer3_1:
	movlw	.16
	cpfseq	ir_s8_counter				; got exactly 16 bytes?
	bra		isr_timer3_2				; NO - test for 17 bytes
	tstfsz	ir_s8_buffer+.15			; YES - last byte = 0x00 ?
	bra		isr_timer3_exit				;       No  - exit
	bra		isr_timer3_ir				;       YES - got 16 bytes, compute local checksum
isr_timer3_2:
	movlw	.17
	cpfseq	ir_s8_counter				; got exactly 17 bytes?
	bra		isr_timer3_exit				; NO  - exit
	bra		isr_timer3_s8				; YES - S8 data

isr_timer3_ir:							; IR input
	movff	ir_s8_buffer+.0,PRODL
	clrf	PRODH
	movf	ir_s8_buffer+.1,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.2,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.3,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.4,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.5,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.6,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.7,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.8,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.9,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.10,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.11,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.12,W
	rcall	isr_timer3_checksum

	; Compare checksum
	movf	ir_s8_buffer+.13,W
	cpfseq	PRODL						; checksum ok?
	bra		isr_timer3_exit				; NO - exit
	movf	ir_s8_buffer+.14,W
	cpfseq	PRODH						; checksum ok?
	bra		isr_timer3_exit				; NO - exit

	; Checksum OK, copy results
	movff	ir_s8_buffer+.1,hud_status_byte
	movff	ir_s8_buffer+.2,o2_mv_sensor1+0
	movff	ir_s8_buffer+.3,o2_mv_sensor1+1
	movff	ir_s8_buffer+.4,o2_mv_sensor2+0
	movff	ir_s8_buffer+.5,o2_mv_sensor2+1
	movff	ir_s8_buffer+.6,o2_mv_sensor3+0
	movff	ir_s8_buffer+.7,o2_mv_sensor3+1
	movff	ir_s8_buffer+.8,o2_ppo2_sensor1
	movff	ir_s8_buffer+.9,o2_ppo2_sensor2
	movff	ir_s8_buffer+.10,o2_ppo2_sensor3
	movff	ir_s8_buffer+.11,hud_battery_mv+0
	movff	ir_s8_buffer+.12,hud_battery_mv+1

	movlw	ir_timeout_value			; multiples of 62.5 ms
	movwf	ir_s8_timeout				; reload timeout

	banksel	hud_status_byte
	bsf		hud_connection_ok			; set manually for hwHUD w/o the HUD module...
	banksel	isr_backup					; select bank 0 for ISR data

isr_timer3_exit:
	clrf	ir_s8_counter				; clear pointer
	bcf		PIR2,TMR3IF					; clear flag
	return

isr_timer3_checksum:
	addwf	PRODL,F
	movlw	.0
	addwfc	PRODH,F
	return

isr_timer3_s8:							; S8 input
	movff	ir_s8_buffer+.0,PRODL
	clrf	PRODH
	movf	ir_s8_buffer+.1,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.2,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.3,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.4,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.5,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.6,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.7,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.8,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.9,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.10,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.11,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.12,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.13,W
	rcall	isr_timer3_checksum
	movf	ir_s8_buffer+.14,W
	rcall	isr_timer3_checksum

	; Compare checksum
	movf	ir_s8_buffer+.15,W
	cpfseq	PRODL						; checksum ok?
	bra		isr_timer3_exit				; NO - exit
	movf	ir_s8_buffer+.16,W
	cpfseq	PRODH						; checksum ok?
	bra		isr_timer3_exit				; NO - exit

	; Checksum OK, copy results
	movff	ir_s8_buffer+.3,hud_status_byte
	movff	ir_s8_buffer+.13,hud_battery_mv+0
	movff	ir_s8_buffer+.14,hud_battery_mv+1

	banksel	common
	btfsc	new_s8_data_available		; =1: old data already processed?
	bra		isr_timer3_skip				; NO - skip copying new results

	movff	ir_s8_buffer+.6,s8_rawdata_sensor1+2
	movff	ir_s8_buffer+.5,s8_rawdata_sensor1+1
	movff	ir_s8_buffer+.4,s8_rawdata_sensor1+0
	movff	ir_s8_buffer+.9,s8_rawdata_sensor2+2
	movff	ir_s8_buffer+.8,s8_rawdata_sensor2+1
	movff	ir_s8_buffer+.7,s8_rawdata_sensor2+0
	movff	ir_s8_buffer+.12,s8_rawdata_sensor3+2
	movff	ir_s8_buffer+.11,s8_rawdata_sensor3+1
	movff	ir_s8_buffer+.10,s8_rawdata_sensor3+0
	banksel	common
	bsf		new_s8_data_available		; set flag

isr_timer3_skip:
	banksel	ir_s8_timeout
	movlw	ir_timeout_value			; multiples of 62.5ms
	movwf	ir_s8_timeout				; reload timeout
	bra		isr_timer3_exit				; exit


;=============================================================================

isr_tmr7:								; each 62.5ms
	bcf		PIR5,TMR7IF					; clear flag
	banksel	0xF16						; addresses F16h through F5Fh, are also used by SFRs, but are not part of the Access RAM
	movlw	.248
	movwf	TMR7H						; rollover after 2048 cycles -> 62.5ms

	banksel	common
	call	get_analog_switches			; get analog readings
	btfss	INTCON3,INT1IE
	bra		isr_tmr7_a
	btfsc	analog_sw2_pressed
	rcall	isr_switch_left
isr_tmr7_a:
	banksel	common
	btfss	INTCON,INT0IE
	bra		isr_tmr7_b
	btfsc	analog_sw1_pressed
	rcall	isr_switch_right
isr_tmr7_b:
	banksel	common
	btfss	no_sensor_int				; sensor interrupt (because it's addressed during sleep)?
	bra		isr_tmr7_c					; NO  - continue
	banksel	isr_backup					; YES - back to bank 0 ISR data
	return
isr_tmr7_c:
	banksel	isr_backup
	movf	max_CCPR1L,W				; dimm value
	cpfseq	CCPR1L						; = current PWM value?
	rcall	isr_dimm_tft				; NO - adjust until max_CCPR1L=CCPR1L

	banksel	isr_backup
	decfsz	ir_s8_timeout,F				; IR data still valid?
	bra		isr_tmr7_2					; YES - continue
	; timeout, clear IR-Data

	movlw	ir_timeout_value			; multiples of 62.5ms
	movwf	ir_s8_timeout				; reload timeout

	banksel	common
	btfss	analog_o2_input
	bra		isr_tmr7_1a					; always with normal ostc3 hardware
	btfss	s8_digital
	bra		isr_tmr7_2					; only when digital
isr_tmr7_1a:
	clrf	o2_mv_sensor1+0				; S8/IR timeout clears all analog input readings to zero -> fallback will be triggered when sensor mode was used
	clrf	o2_mv_sensor1+1
	clrf	o2_mv_sensor2+0
	clrf	o2_mv_sensor2+1
	clrf	o2_mv_sensor3+0
	clrf	o2_mv_sensor3+1
	banksel	hud_battery_mv
	clrf	hud_battery_mv+0
	clrf	hud_battery_mv+1
	banksel	hud_status_byte
	clrf	hud_status_byte
	clrf	o2_ppo2_sensor1				; for IR/S8 UD
	clrf	o2_ppo2_sensor2
	clrf	o2_ppo2_sensor3

	banksel	common
	bsf		new_s8_data_available		; set flag to update in surface mode

isr_tmr7_2:
	banksel	common
	btfss	no_sensor_int				; sensor interrupt (because it's addressed during sleep)?
	bra		isr_sensor_state2			; NO  - continue
	banksel	isr_backup					; YES - back to Bank0 ISR data
	return

isr_sensor_state2:
	banksel	common
	movff	sensor_state_counter,WREG
	btfss	WREG,0						; every 1/4 second
	bsf		quarter_second_update		; set flag
	banksel	isr_backup					; back to Bank0 ISR data
	movlw	d'2'						; coding for normal speed
	cpfseq	cpu_speed_state				; CPU running on normal speed?
	rcall	isr_set_speed_to_normal		; NO - set CPU speed to normal

	incf	sensor_state_counter,F		; counts to eight for state machine

; State 1: Clear flags and average registers, get temperature (51 us) and start pressure integration (73.5 us)
; State 2: Get pressure    (51 us), start temperature integration (73.5 us) and calculate temperature compensated pressure (233 us)
; State 3: Get temperature (51 us) and start pressure integration (73.5 us)
; State 4: Get pressure    (51 us), start temperature integration (73.5 us) and calculate temperature compensated pressure (233 us)
; State 5: Get temperature (51 us) and start pressure integration (73.5 us)
; State 6: Get pressure    (51 us), start temperature integration (73.5 us) and calculate temperature compensated pressure (233 us)
; State 7: Get temperature (51 us) and start pressure integration (73.5 us)
; State 8: Get pressure    (51 us), start temperature integration (73.5 us),    calculate temperature compensated pressure (233 us) and build average for half-second update of temperature and pressure

	movff	sensor_state_counter,WREG		; WREG used as temp here...
	dcfsnz	WREG,F
	bra		sensor_int_state1_plus_restart	; do State 1
	dcfsnz	WREG,F
	bra		sensor_int_state2				; do State 2
	dcfsnz	WREG,F
	bra		sensor_int_state1				; do State 3
	dcfsnz	WREG,F
	bra		sensor_int_state2				; do State 4
	dcfsnz	WREG,F
	bra		sensor_int_state1				; do State 5
	dcfsnz	WREG,F
	bra		sensor_int_state2				; do State 6
	dcfsnz	WREG,F
	bra		sensor_int_state1				; do State 7
;	bra		sensor_int2_plus_average		; do State 8
;sensor_int2_plus_average:
	; First, do state2:
	call	get_pressure_value			; state 2: get pressure (51 us)
	call	get_temperature_start		; and start temperature integration (73.5 us)
	call	calculate_compensation		; calculate temperature compensated pressure (27 us)
; Build average
	bcf		STATUS,C					; clear carry bit
	rrcf	amb_pressure_avg+1			; amb_pressure sum / 2
	rrcf	amb_pressure_avg+0
	bcf		STATUS,C					; clear carry bit, twice
	rrcf	amb_pressure_avg+1			; amb_pressure sum / 4
	rrcf	amb_pressure_avg+0

	movff	amb_pressure_avg+1,amb_pressure+1	; copy into actual register
	movff	amb_pressure_avg+0,amb_pressure+0

	bcf		STATUS,C
	btfsc	temperature_avg+1,7			; copy sign bit to carry
	bsf		STATUS,C
	rrcf	temperature_avg+1			; signed temperature /2
	rrcf	temperature_avg+0
	bcf		STATUS,C
	btfsc	temperature_avg+1,7			; copy sign bit to carry
	bsf		STATUS,C
	rrcf	temperature_avg+1			; signed temperature /4
	rrcf	temperature_avg+0

	movff	temperature_avg+1,temperature+1		; copy into actual register
	movff	temperature_avg+0,temperature+0

	banksel	common						; flag1 is in bank 1
	bcf		temp_changed				; clear flag for temperature update
	bcf		pressure_refresh			; clear flag for pressure update
	banksel	isr_backup					; back to bank 0 ISR data

	; Temp changed?
	movf	temperature+0,W
	cpfseq	last_temperature+0
	bra		isr_sensor_state2_2			; YES
	movf	temperature+1,W
	cpfseq	last_temperature+1
	bra		isr_sensor_state2_2			; YES

	bra		isr_sensor_state2_3			; no change

isr_sensor_state2_2:
	banksel	common						; flag1 is in bank 1
	bsf		temp_changed				; YES
	banksel	isr_backup					; back to bank 0 ISR data
isr_sensor_state2_3:
	movff	temperature+0,last_temperature+0	; copy for compare
	movff	temperature+1,last_temperature+1

;	movf	amb_pressure+0,W
;	cpfseq	last_pressure+0
;	bra		isr_sensor_state2_4			; YES
;	movf	amb_pressure+1,W
;	cpfseq	last_pressure+1
;	bra		isr_sensor_state2_4			; YES
;
;	bra		isr_sensor_state2_5			; no change
;isr_sensor_state2_4:
	banksel	common						; flag1 is in bank 1
	bsf		pressure_refresh			; Always set this flag
	banksel	isr_backup					; back to bank 0 ISR data
;isr_sensor_state2_5:
;	movff	amb_pressure+0,last_pressure+0	; copy for compare
;	movff	amb_pressure+1,last_pressure+1

	clrf	sensor_state_counter		; reset state counter
	banksel	common						; flag2 is in bank 1
	btfss	simulatormode_active		; are we in simulator mode?
	bra		comp_air_pressure			; NO
	bsf		pressure_refresh			; always set pressure_refresh flag in simulator mode
	banksel	isr_backup					; back to bank 0 ISR data
	movlw	LOW  d'1000'				; simulate 1000 mbar surface pressure
	movwf	last_surfpressure+0
	movlw	HIGH d'1000'
	movwf	last_surfpressure+1

comp_air_pressure:
	banksel	isr_backup					; back to bank 0 ISR data
	movf	last_surfpressure+0,W		; compensate air pressure
	subwf	amb_pressure+0,W
	movwf	rel_pressure+0				; rel_pressure stores depth

	movf	last_surfpressure+1,W
	subwfb	amb_pressure+1,W
	movwf	rel_pressure+1
	btfss	STATUS,N					; is result below zero?
	bra		sensor_int_state_exit		; NO
	clrf	rel_pressure+0				; YES - do not display negative depths
	clrf	rel_pressure+1				; e.g. when surface air pressure dropped during the dive
	bra		sensor_int_state_exit

sensor_int_state1_plus_restart:
	clrf	amb_pressure_avg+0			; pressure average registers
	clrf	amb_pressure_avg+1
	clrf	temperature_avg+0
	clrf	temperature_avg+1

sensor_int_state1:
	call	get_temperature_value		; state 1: get temperature...
	call	get_pressure_start			; ...and start pressure integration
	bra		sensor_int_state_exit

sensor_int_state2:
	call	get_pressure_value			; state 2: get pressure (51 us)...
	call	get_temperature_start		; ...and start temperature integration (73.5 us)
	call	calculate_compensation		; .. and calculate temperature compensated pressure (233 us)
	;bra	sensor_int_state_exit

sensor_int_state_exit:
	rcall	isr_restore_clock			; restore clock
	return

;=============================================================================

isr_rtcc:								; each second
	bcf		PIR3,RTCCIF					; clear flag
	banksel	0xF16						; addresses, F16h through F5Fh, are also used by SFRs, but are not part of the access RAM
	bsf		RTCCFG,RTCPTR1
	bsf		RTCCFG,RTCPTR0				; year
	movff	RTCVALL,year				; format is BCD
	movff	RTCVALH,day					; dummy read
	movff	RTCVALL,day					; format is BCD
	movff	RTCVALH,month				; format is BCD
	movff	RTCVALL,hours				; format is BCD
	movff	RTCVALH,secs				; format is BCD
	movff	RTCVALL,secs				; format is BCD
	movff	RTCVALH,mins				; format is BCD
	banksel	isr_backup					; back to bank 0 ISR data

	; Convert BCD to DEC and set registers
	movff	mins, isr1_temp
	rcall	isr_rtcc_convert			; converts to dec with result in WREG
	movff	WREG,mins
	movff	secs, isr1_temp
	rcall	isr_rtcc_convert			; converts to dec with result in WREG
	movff	WREG,secs
	movff	hours, isr1_temp
	rcall	isr_rtcc_convert			; converts to dec with result in WREG
	movff	WREG,hours
	movff	month, isr1_temp
	rcall	isr_rtcc_convert			; converts to dec with result in WREG
	movff	WREG,month
	movff	day, isr1_temp
	rcall	isr_rtcc_convert			; converts to dec with result in WREG
	movff	WREG,day
	movff	year, isr1_temp
	rcall	isr_rtcc_convert			; converts to dec with result in WREG
	movff	WREG,year

	; Place once/second tasks for ISR here (Be sure of the right bank!)
	banksel	common						; flag1 is in bank 1
	btfss	sleepmode					; in sleepmode?
	call	get_ambient_level			; NO - get ambient light level and set max_CCPR1L

	rcall	isr_battery_gauge			; add amount of battery consumption to battery_gauge:6

	; update uptime
	banksel	uptime+0
	incf	uptime+0,F
	movlw	.0
	addwfc	uptime+1,F
	addwfc	uptime+2,F
	addwfc	uptime+3,F

	banksel	common						; flag1 is in bank 1
	bsf		onesecupdate				; a new second has begun
	btfsc	divemode					; in divemode?
	rcall	isr_divemode_1sec			; YES - do some divemode stuff in bank common

	btfss	divemode					; in divemode?
	rcall	isr_update_lastdive_time	; NO - update the last dive timer

	tstfsz	secs						; secs == 0 ?
	return								; NO - done

	bsf		oneminupdate				; a new minute has begun

	btfss	divemode					; in Divemode?
	rcall	check_nofly_desat_time		; NO - so increase interval

	; Check if a new hour has just begun
	tstfsz	mins						; mins == 0 ?
	bra		isr_rtcc2					; NP
	bsf		onehourupdate				; YES - set flag

isr_rtcc2:
	banksel	isr_backup					; back to bank 0 ISR data
	return								; done

isr_update_lastdive_time:				; called every second when not in divemode
	; update uptime
	banksel	lastdive_time+0
	incf	lastdive_time+0,F
	movlw	.0
	addwfc	lastdive_time+1,F
	addwfc	lastdive_time+2,F
	addwfc	lastdive_time+3,F
	banksel	common
	return

isr_battery_gauge:
	banksel	isr_backup					; bank 0 ISR data
	movlw	current_sleepmode			; 100ľA/3600 -> nAs (sleepmode current)
	movwf	isr1_temp					; store value (low byte)
	clrf	isr2_temp					; high byte

	banksel	common						; flag1 is in bank 1
	btfss	sleepmode					; in sleepmode?
	rcall	isr_battery_gauge2			; NO - compute current consumption value into isr1_temp and isr2_temp

	banksel	isr_backup					; bank 0 ISR data
	movf	isr1_temp,W					; 48 Bit add of isr1_temp and isr2_temp into battery_gauge:6
	addwf	battery_gauge+0,F
	movf	isr2_temp,W
	addwfc	battery_gauge+1,F
	movlw	.0
	addwfc	battery_gauge+2,F
	addwfc	battery_gauge+3,F
	addwfc	battery_gauge+4,F
	addwfc	battery_gauge+5,F
	return

isr_battery_gauge2:
	; set consumption rate in nAs for an one second interval
	; Example:
	; movlw	LOW  .55556					; 0,2A/3600*1e9s = nAs
	; movwf	isr1_temp					; low byte
	; movlw	HIGH .55556					; 0,2A/3600*1e9s = nAs
	; movwf	isr2_temp					; high byte

	; Current consumption for LED backlight is 47*CCPR1L+272
	movf	CCPR1L,W
	mullw	current_backlight_multi
	movlw	LOW  current_backlight_offset
	addwf	PRODL,F
	movlw	HIGH current_backlight_offset
	addwfc	PRODH,F
	movff	PRODL,isr1_temp
	movff	PRODH,isr2_temp				; isr1_temp and isr2_temp hold value for backlight

	; Add current for CPU and GPU 
	; cpu_speed_state=1: ECO (3.1mA -> 861nAs), =2: NORMAL (5.50mA -> 1528nAs) or =3: FASTEST (8.04mA -> 2233nAs)
	banksel	isr_backup					; Bank0 ISR data
	movlw	.1
	cpfseq	cpu_speed_state
	bra		isr_battery_gauge3
	movlw	LOW  current_speed_eco
	addwf	isr1_temp,F
	movlw	HIGH current_speed_eco
	addwfc	isr2_temp,F
	bra		isr_battery_gauge5
isr_battery_gauge3:
	movlw	.2
	cpfseq	cpu_speed_state
	bra		isr_battery_gauge4
	movlw	LOW  current_speed_normal
	addwf	isr1_temp,F
	movlw	HIGH current_speed_normal
	addwfc	isr2_temp,F
	bra		isr_battery_gauge5
isr_battery_gauge4:
	movlw	LOW  current_speed_fastest
	addwf	isr1_temp,F
	movlw	HIGH current_speed_fastest
	addwfc	isr2_temp,F
isr_battery_gauge5:
	; Add current if IR receiver is on
	btfss	ir_power					; IR enabled?
	bra		isr_battery_gauge6			; NO
	movlw	LOW  current_ir_receiver
	addwf	isr1_temp,F
	movlw	HIGH current_ir_receiver
	addwfc	isr2_temp,F
isr_battery_gauge6:
	; Add current for compass/accelerometer
	btfss	compass_enabled				; compass active?
	bra		isr_battery_gauge7			; NO
	movlw	LOW  current_compass
	addwf	isr1_temp,F
	movlw	HIGH current_compass
	addwfc	isr2_temp,F
isr_battery_gauge7:
	return

isr_divemode_1sec:
	incf	samplesecs,F				; "samplingrate" diving seconds done 
	decf	samplesecs_value,W			; holds "samplingrate" value (minus 1 into WREG)
	cpfsgt	samplesecs					; done?
	bra		isr_divemode_1sec2			; NO

	clrf	samplesecs					; clear counter...
	bsf		store_sample				; ...and set bit for profile storage
isr_divemode_1sec2:
	; increase total divetime (regardless of start_dive_threshold)
	infsnz	total_divetime_seconds+0,F
	incf	total_divetime_seconds+1,F	; total dive time (regardless of start_dive_threshold)

	btfss	divemode2					; displayed divetime is running?
	return								; NO (e.g. too shallow)

	; increase divetime registers (displayed dive time)
	incf	divesecs,F
	movlw	d'59'
	cpfsgt	divesecs
	bra		isr_divemode_1sec2a

	clrf	divesecs
	bsf		realdive					; this bit is always set (again) if the dive is longer then one minute
	infsnz	divemins+0,F
	incf	divemins+1,F				; increase divemins

isr_divemode_1sec2a:
	btfss	FLAG_apnoe_mode				; are we in apnoe mode?
	return								; NO

	incf	apnoe_secs,F				; increase descent registers
	movlw	d'59'
	cpfsgt	apnoe_secs					; full minute?
	return								; NO
	clrf	apnoe_secs
	incf	apnoe_mins,F				; increase descent mins
	return

;=============================================================================
; BCD to Binary conversion.
; Input: isr1_temp = Value in BCD
; Output WREG = value in binary.
isr_rtcc_convert:
	swapf	isr1_temp, W
	andlw	0x0F						; W = tens
	rlncf	WREG, W						; W = 2*tens
	subwf	isr1_temp, F				; 16*tens + ones - 2*tens
	subwf	isr1_temp, F				; 14*tens + ones - 2*tens
	subwf	isr1_temp, W				; 12*tens + ones - 2*tens
	return

;=============================================================================

isr_switch_right:
	bcf		INTCON,INT0IE				; disable INT0
	banksel	common						; flag1 is in bank 1
	btfss	flip_screen					; 180° flipped?
	bsf		switch_right				; set flag
	btfsc	flip_screen					; 180° flipped?
	bsf		switch_left					; set flag
	bra		isr_switch_common			; continue...

isr_switch_left:
	bcf		INTCON3,INT1IE				; disable INT1
	banksel	common						; flag1 is in bank 1
	btfss	flip_screen					; 180° flipped?
	bsf		switch_left					; set flag
	btfsc	flip_screen					; 180° flipped?
	bsf		switch_right				; set flag
isr_switch_common:
	; load timer1 for first press
	clrf	TMR1L
	movlw	TMR1H_VALUE_FIRST			; in steps of 7.8125 ms
	movwf	TMR1H
	bsf		T1CON,TMR1ON				; start timer 1
	banksel	isr_backup					; select bank 0 for ISR data
	bcf		INTCON3,INT1IF				; clear flag
	bcf		INTCON,INT0IF				; clear flag
	return

timer1int:
	bcf		PIR1,TMR1IF					; clear flag
	banksel	common						; flag1 is in bank 1
	bcf		INTCON,INT0IF				; clear flag
	bcf		INTCON3,INT1IF				; clear flag
	; digital
	btfss	switch_left1				; left button hold-down?
	bra		timer1int_left				; YES
	btfss	switch_right2				; right button hold-down?
	bra		timer1int_right				; YES

	; Analog
	btfsc	analog_sw2_pressed			; left button hold-down?
	bra		timer1int_left				; YES
	btfsc	analog_sw1_pressed			; right button hold-down?
	bra		timer1int_right				; YES

	; No button hold-down, stop Timer 1
	bcf		T1CON,TMR1ON				; stop timer 1
	bsf		INTCON,INT0IE				; enable INT0
	bsf		INTCON3,INT1IE				; enable INT1
	return

timer1int_left:
	btfss	flip_screen					; 180° flipped?
	bsf		switch_left					; (re-)set flag
	btfsc	flip_screen					; 180° flipped?
	bsf		switch_right				; (re-)set flag
	bra		timer1int_common			; continue
timer1int_right:
	btfss	flip_screen					; 180° flipped?
	bsf		switch_right				; set flag
	btfsc	flip_screen					; 180° flipped?
	bsf		switch_left					; set flag
timer1int_common:
	; load timer1 for next press
	clrf	TMR1L
	movlw	TMR1H_VALUE_CONT			; surface mode
	btfsc	divemode
	movlw	TMR1H_VALUE_CONT_DIVE		; sive mode
	movwf	TMR1H
	return								; return from timer1int with timer1 kept running

;=============================================================================

check_nofly_desat_time:					; called every minute when not in divemode
	banksel	int_O_desaturation_time
	movf	int_O_desaturation_time+0,W	; is Desat null ?
	iorwf	int_O_desaturation_time+1,W
	bz		check_nofly_desat_time_1	; YES

	; int_O_desaturation_time is only computed while in start, surface mode, menue_tree or ghostwriter.
	; So the ISR may clock surface_interval past the actual surface interval time. But TFT_surface_lastdive
	; will check int_O_desaturation_time and in case int_O_desaturation_time is zero it will not show
	; surface_interval but lastdive_time instead. So this glitch remains invisible.

	; Increase surface interval timer
	banksel	common
	infsnz	surface_interval+0,F
	incf	surface_interval+1,F
	return								; done

check_nofly_desat_time_1:
	banksel	common
	clrf	surface_interval+0
	clrf	surface_interval+1			; clear surface interval timer
	return								; done

;=============================================================================

isr_restore_clock:
	movff	cpu_speed_request,cpu_speed_state	; acknowledge CPU speed request
	banksel	isr_backup
	movlw	d'1'
	cpfseq	cpu_speed_request
	bra		isr_restore_speed2
	; Reset to eco
	movlw	b'00000000'
	movwf	OSCTUNE						; 4x PLL Ddsable (Bit 6) - only works with 8 or 16MHz (=32 or 64MHz)
	movlw	b'00110010'
	movwf	OSCCON						; 1 MHz INTOSC
	movlw	T2CON_ECO
	movwf	T2CON
	bra		isr_restore_exit
isr_restore_speed2:
	movlw	d'2'
	cpfseq	cpu_speed_request
	bra		isr_restore_speed3
	; Reset to normal
	movlw	b'01110010'
	movwf	OSCCON						; 16 MHz INTOSC
	movlw	b'00000000'
	movwf	OSCTUNE						; 4x PLL disable (Bit 6) - only works with 8 or 16MHz (=32 or 64MHz)
	movlw	T2CON_NORMAL
	movwf	T2CON
	bra		isr_restore_exit
isr_restore_speed3:
	; Reset to fastest
	movlw	b'01110010'					; 16 MHz INTOSC
	movwf	OSCCON
	movlw	b'01000000'
	movwf	OSCTUNE						; 4x PLL enable (Bit 6) - only works with 8 or 16MHz (=32 or 64MHz)
	movlw	T2CON_FASTEST
	movwf	T2CON
	;bra	isr_restore_exit
isr_restore_exit:
	btfss	OSCCON,HFIOFS
	bra		isr_restore_exit			; loop until PLL is stable
	return


restore_flash:							; restore first flash page from EEPROM
	banksel	common
	; Start address in internal flash
	movlw	0x00
	movwf	TBLPTRL
	movwf	TBLPTRH
	movwf	TBLPTRU

	movlw	b'10010100'					; setup erase
	rcall	Write						; write

	movlw	.128
	movwf	lo							; byte counter
	clrf	EEADR
	movlw	.3
	movwf	EEADRH						; setup backup address

	TBLRD*-								; dummy read to be in 128 byte block
restore_flash_loop:
	call	read_eeprom
	incf	EEADR,F
	movff	EEDATA,TABLAT				; put 1 byte
	tblwt+*								; table write with pre-increment
	decfsz	lo,F						; 128 bytes done?
	bra		restore_flash_loop			; NO - loop

	movlw	b'10000100'					; setup writes
	rcall	Write						; write

	reset								; done, reset CPU

Write:
	movwf	EECON1						; type of memory to write in
	movlw	0x55
	movwf	EECON2
	movlw	0xAA
	movwf	EECON2
	bsf		EECON1,WR					; write
	nop
	nop
	return

	END