view src/isr.asm @ 642:a9a0188091e4

fix rare upgrade issue with OSTC sport 2019 hardware
author heinrichsweikamp
date Thu, 14 Jan 2021 16:24:07 +0100
parents 8c1f1f334275
children 7d8a4c60ec1a 5b7fe7777425
line wrap: on
line source

;=============================================================================
;
;   File isr.asm                            * combined next generation V3.11.1
;
;   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"

	extern	restore_flash


;=============================================================================
; Code to be placed at a fixed Position
;
isr_high	CODE	0x0008				; high priority interrupts
	bra		HighInt						; jump to ISR

isr_low		CODE	0x00018				; low priority interrupts *** not used ***
	retfie	FAST						; do an immediate return from IRQ
;
;=============================================================================


;-----------------------------------------------------------------------------
; Interrupt Dispatcher Entry Point
;
HighInt:
	; initialize interrupt code
	banksel	isr_backup					; default bank for all ISR code is bank ISR data
	movff	PRODL,PROD_backup+0			; back-up PRODL
	movff	PRODH,PROD_backup+1			; back-up PRODH
	; serve buttons
	btfsc	PIR1,TMR1IF					; timer 1 interrupt (button hold-down timer)?
	rcall	timer1int					; YES - reset timer
	btfsc	PIR5,TMR4IF				; timer 4 interrupt (button debounce)
	rcall	timer4int				; YES, serve the interrupt
	btfsc	INTCON,INT0IF				; right button activity?
	rcall	isr_switch_right			; YES - check right switch
	btfsc	INTCON3,INT1IF				; left button activity?
	rcall	isr_switch_left				; YES - check left switch

 IFDEF _external_sensor
	; serve IR/S8 link timer
	btfsc	PIR3,RC2IF					; UART 2 interrupt?
	rcall	isr_uart2					; YES - get a byte from the IR/S8 link
	btfsc	PIR2,TMR3IF					; timer 3 interrupt?
	rcall	isr_timer3					; YES - check bytes received from IR/S8 link for being a valid telegram
 ELSE
	bcf		PIR3,RC2IF					; clear UART 2  interrupt
	bcf		PIR2,TMR3IF					; clear timer 3 interrupt
	; fill-up to keep code size identical to _external_sensor variant, see "Attention" below
	nop
	nop
 ENDIF

	; serve pressure and temperature sensor
	btfsc	PIR5,TMR7IF					; timer 7 interrupt?
	rcall	isr_tmr7					; YES - do every 62.5 ms tasks: read sensors, set CPU speed

	; serve real-time clock (RTCC)
	btfsc	PIR3,RTCCIF					; real-time-clock interrupt?
	rcall	isr_rtcc					; YES - do every 1/2 s tasks: read RTC, trigger timed tasks, adjust CPU speed, gauge battery, etc.

	; clean up and exit
	movff	PROD_backup+0,PRODL			; restore PRODL
	movff	PROD_backup+1,PRODH			; restore PRODH
	bsf		trigger_isr_updates			; signal that the ISR had kicked in
	retfie	FAST						; return from interrupt restoring BSR, STATUS and WREG


;-----------------------------------------------------------------------------
; CPU Speed Adjustment
;
isr_adjust_speed:
	movff	cpu_speed_request,cpu_speed_state	; acknowledge CPU speed request

	btfsc	speed_is_eco				; speed 'eco' requested?
	bra		isr_set_speed_to_eco		; YES - set eco speed
	btfsc	speed_is_fastest			; NO  - speed 'fastest' requested?
	bra		isr_set_speed_to_fastest	;       YES - set fastest speed
	;bra	isr_set_speed_to_normal		;       NO  - default to normal speed

isr_set_speed_to_normal:
	clrf	OSCTUNE						; switch off x4 PLL
	movlw	b'01110010'					; select 16 MHz
	movwf	OSCCON						; set prescaler
	movlw	T2CON_NORMAL				; PWM1 dimming factor for speed 'normal'
	bra		isr_adjust_speed_exit

isr_set_speed_to_eco:
	clrf	OSCTUNE						; switch off x4 PLL
	movlw	b'00110010'					; select 1 MHz
	movwf	OSCCON						; set prescaler
	movlw	T2CON_ECO					; PWM1 dimming factor for speed 'eco'
	bra		isr_adjust_speed_exit

isr_set_speed_to_fastest:
	movlw	b'01110010'					; select 16 MHz by default
	btfsc	lv_core						; on OSTC with low voltage core?
	movlw	b'01100010'					; YES - reduce to 8 MHz
	movwf	OSCCON						; set prescaler
	bsf		OSCTUNE,6					; switch on  x4 PLL -> 64 MHz on high voltage core, 32 MHz on low voltage core
	movlw	T2CON_FASTEST				; PWM1 dimming factor for speed 'fastest'
	bra	isr_adjust_speed_exit

	; Attention: fill-up the gap between the end of this section
	;            and the next section which starts at 0x00080 !!
	nop
	
block_0_code_end:						; marker to find end of code in block 0 in linker report file


;=============================================================================
; Code to be placed at a fixed Position: Jump-Vector for the Bootloader
;
restore		CODE	0x00080				; restore first flash page from EEPROM

restore_flash_0x00080:
	goto	restore_flash
;
;=============================================================================


;=============================================================================
isr_handler	CODE	0x00084
;=============================================================================

isr_adjust_speed_exit:
	movwf	T2CON						; adjust PWM1 for LED dimming
	btfss	OSCCON,HFIOFS				; PLL stabilized?
	bra		isr_adjust_speed_exit		; NO  - loop to give it some more time
	return								; YES - done
	
;-----------------------------------------------------------------------------
; Handle digitally-attached external Sensors
;
; take a byte received on IR/S8 link and slot it into the RX buffer
;
 IFDEF _external_sensor

isr_uart2:
	bcf		PIR3,RC2IF					; clear UART 2 interrupt flag
	banksel	RCREG2						; RC*2 is outside access RAM
	movff	RCREG2,isr_lo				; copy received byte to isr_lo
	bcf		RCSTA2,CREN					; clear receiver status
	bsf		RCSTA2,CREN					; ...
	banksel	isr_backup					; back to default ISR bank
	movlw	.18							; size of the buffer
	cpfslt	ir_s8_counter				; number of received bytes < buffer size?
	bra		isr_uart2_1					; NO  - buffer full, do not store the byte
	movf	ir_s8_counter,W				; YES - copy number of received bytes to WREG
	MOVII	FSR0L,FSR0_backup			;     - back-up FSR0
	lfsr	FSR0,ir_s8_buffer			;     - load base address of buffer
	movff	isr_lo,PLUSW0				;     - store received byte
	MOVII	FSR0_backup,FSR0L			;     - restore FSR0
	incf	ir_s8_counter,F				;     - increment number of received bytes by 1
isr_uart2_1:
	movlw	.253						; reload timer 3, high byte
	movwf	TMR3H						; ...
	clrf	TMR3L						; reload timer 3, low  byte
	bsf		T3CON,TMR3ON				; restart timer
	return								; done


;-----------------------------------------------------------------------------
; Timeout on IR/S8 Link: check the Checksum and gather the received Data
;
isr_timer3:
	bcf		T3CON,TMR3ON				; stop timer 3
	movlw	.15							; a IR telegram has 15 bytes
	cpfseq	ir_s8_counter				; got exactly 15 bytes?
	bra		isr_timer3_1				; NO  - test for 16 bytes
	bra		isr_timer3_ir				; YES - got 15 bytes, compute local checksum
isr_timer3_1:
	movlw	.16							; a IR telegram may also have 16 bytes, with last byte 0x00
	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							; a S8 telegram has 17 bytes
	cpfseq	ir_s8_counter				; got exactly 17 bytes?
	bra		isr_timer3_exit				; NO  - exit
	bra		isr_timer3_s8				; YES - S8 data

	; process telegram received on IR link
isr_timer3_ir:
	movlw	.12							; compute checksum over 1st and next 12 bytes
	rcall	compute_IR_S8_checksum		; compute checksum
	tstfsz	ir_s8_counter				; checksum ok?
	bra		isr_timer3_exit				; NO - discard data

	; copy received data to respective variables
	movff	ir_s8_buffer+.1, hud_status_byte
	movff	ir_s8_buffer+.2, sensor1_mv+0
	movff	ir_s8_buffer+.3, sensor1_mv+1
	movff	ir_s8_buffer+.4, sensor2_mv+0
	movff	ir_s8_buffer+.5, sensor2_mv+1
	movff	ir_s8_buffer+.6, sensor3_mv+0
	movff	ir_s8_buffer+.7, sensor3_mv+1
	movff	ir_s8_buffer+.8, sensor1_ppO2
	movff	ir_s8_buffer+.9, sensor2_ppO2
	movff	ir_s8_buffer+.10,sensor3_ppO2
	movff	ir_s8_buffer+.11,hud_battery_mv+0
	movff	ir_s8_buffer+.12,hud_battery_mv+1

	bsf		hud_connection_ok			; set manually for hwHUD w/o the HUD module
	bra		isr_timer3_reload			; reload timer and exit

	; process telegram received on S8 link
isr_timer3_s8:
	movlw	.14							; compute checksum over 1st and next 14 bytes
	rcall	compute_IR_S8_checksum		; compute checksum
	tstfsz	ir_s8_counter				; checksum ok?
	bra		isr_timer3_exit				; NO - discard data

	; copy received data to respective variables
	movff	ir_s8_buffer+.3, hud_status_byte	; also sets hud_connection_ok flag
	movff	ir_s8_buffer+.13,hud_battery_mv+0
	movff	ir_s8_buffer+.14,hud_battery_mv+1

;	btfsc	trigger_S8_data_update		; last data already processed?
;	bra		isr_timer3_exit				; NO  - skip copying new data (and not reload the timeout)
	bsf		trigger_S8_data_update		; YES - set flag for new data available

	; copy more received data to respective variables
	movff	ir_s8_buffer+.4, s8_rawdata_sensor1+0
	movff	ir_s8_buffer+.5, s8_rawdata_sensor1+1
	movff	ir_s8_buffer+.6, s8_rawdata_sensor1+2
	movff	ir_s8_buffer+.7, s8_rawdata_sensor2+0
	movff	ir_s8_buffer+.8, s8_rawdata_sensor2+1
	movff	ir_s8_buffer+.9, s8_rawdata_sensor2+2
	movff	ir_s8_buffer+.10,s8_rawdata_sensor3+0
	movff	ir_s8_buffer+.11,s8_rawdata_sensor3+1
	movff	ir_s8_buffer+.12,s8_rawdata_sensor3+2

isr_timer3_reload:
	movlw	ir_timeout_value			; get timeout value (in multiples of 62.5 ms)
	movwf	ir_s8_timeout				; reload timeout counter
isr_timer3_exit:
	clrf	ir_s8_counter				; clear number of received bytes
	bcf		PIR2,TMR3IF					; clear IRQ flag
	return								; done


;-----------------------------------------------------------------------------
; Helper Function - Compute Checksum on Data in RX Buffer
;
compute_IR_S8_checksum:
	movwf	ir_s8_counter				; initialize loop counter from WREG
	MOVII	FSR0L,FSR0_backup			; back-up FSR0
	lfsr	FSR0,ir_s8_buffer			; load base address of the receive buffer
	movff	POSTINC0,isr_mpr+0			; initialize low byte of the calculated checksum with first byte in buffer
	clrf	         isr_mpr+1			; clear the high byte of the calculated checksum
compute_IR_S8_checksum_loop:
	movf	POSTINC0,W					; read next byte
	addwf	isr_mpr+0,F					; add it to the to checksum, low  byte
	movlw	.0							; no explicit data to add to the high byte...
	addwfc	isr_mpr+1,F					; ... besides the carry
	decfsz	ir_s8_counter,F				; decrement number of bytes yet to do, all done?
	bra		compute_IR_S8_checksum_loop	; NO  - loop
	movf	POSTINC0,W					; YES - read     low  byte of the received   checksum
	cpfseq	isr_mpr+0					;     - equal to low  byte of the calculated checksum?
	incf	ir_s8_counter,F				;       NO - mark a checksum error
	movf	POSTINC0,W					;     - read     high byte of the received   checksum
	cpfseq	isr_mpr+1					;     - equal to high byte of the calculated checksum?
	incf	ir_s8_counter,F				;       NO - mark a checksum error
	MOVII	FSR0_backup,FSR0L			;     - restore FSR0
	return								;     - done

 ENDIF	; _external_sensor

 
;-----------------------------------------------------------------------------
; Timer 4 - Button debounce (For new digital piezo circuit)
 
timer4int:
	bcf	PIR5,TMR4IF
	decfsz	debounce_counter,F
	return
	bcf 	T4CON,TMR4ON		; Stop timer 4
	clrf	TMR4			; reset
	
	movff	opt_cR_button_right,WREG		; 20-100; mH: opt_cR_button_right will also affect left button 
	bcf	STATUS,C						; clear carry bit
	rrcf	WREG							; /2 -> 10-50
	bcf	STATUS,C						; clear carry bit
	rrcf	WREG							; /2 -> 5-25
	decf	WREG,W							; -1
	decf	WREG,W							; -1
	decf	WREG,W							; -1 -> 2-22
	
;	movlw   .5			; initial delay
	movwf	debounce_counter	; multiples of 16ms 
	return

timer4_restart:
	movlw   .5			; extra delay
	movwf	debounce_counter
	clrf	TMR4			; reset
	bcf	INTCON3,INT1IF		; clear ext. int 1 request
	bcf	INTCON,INT0IF		; clear ext. int 0 request
	bsf		INTCON,INT0IE	; enable INT0 IRQ
	bsf		INTCON3,INT1IE	; enable INT1 IRQ
	return

;-----------------------------------------------------------------------------
; Tasks every 62.5 ms: Buttons, Dimming, Pressure/Temperature Sensor and CPU Speed
;
isr_tmr7:
	bcf		PIE5,TMR7IE					; disable IRQs by TMR7

	banksel	0xF16						; TMR7H/L are not part of the access RAM
	movlw	.248						; reload timer 7, high byte (8x256 ticks -> 62.5 ms)
	movwf	TMR7H						; ...                       (keep low byte running )

	btfss	update_surface_pressure			; shall update the surface pressure?
	bra		isr_tmr7_1						; NO  - skip
	bcf		update_surface_pressure			; YES - clear request flag
	MOVII	pressure_abs_ref,pressure_surf	;     - update surface pressure

isr_tmr7_1:
	call	get_analog_switches			; get analog readings - bank-safe, but CAUTION: returns in bank common
	banksel	isr_backup					; back to ISR default bank

	btfss	INTCON3,INT1IE				; external IRQ 1 enabled?
	bra		isr_tmr7_2					; NO  - skip next
	btfsc	analog_sw2_pressed			; YES - analog switch 2 pressed?
	rcall	isr_switch_left				;       NO - get digital readings of left switch

isr_tmr7_2:
	btfss	INTCON,INT0IE				; external IRQ 0 enabled?
	bra		isr_tmr7_3					; NO  - skip next
	btfsc	analog_sw1_pressed			; YES - analog switch 1 pressed?
	rcall	isr_switch_right			;       NO - get digital readings of right switch

isr_tmr7_3:
	btfsc	block_sensor_interrupt		; sensor interrupts disabled?
	bra		sensor_int_state_exit		; YES - goto exit
	;bra	isr_tmr7_4					; NO  - continue

isr_tmr7_4:
	movf	max_CCPR1L,W				; dim value
	cpfseq	CCPR1L						; = current PWM value?
	rcall	isr_dimm_tft				; NO - adjust until max_CCPR1L = CCPR1L

 IFDEF _external_sensor

	decfsz	ir_s8_timeout,F				; decrement IR/S8 timeout counter, became zero?
	bra		isr_sensor_state2			; NO  - continue with sensor
	movlw	ir_timeout_value			; YES - get timeout value (in multiples of 62.5 ms)
	movwf	ir_s8_timeout				;     - reload timeout timer
	btfsc	ext_input_optical			;     - optical input in use?
	bra		isr_tmr7_5					;       YES - clear data
	TSTOSS	opt_s8_mode					;       NO  - S8 input in use?
	bra		isr_sensor_state2			;             NO  - must be analog interface in use, keep data
	;bra	isr_tmr7_5					;             YES - clear data

isr_tmr7_5:
	clrf	hud_status_byte				; S8/IR timeout clears all analog input readings to zero -> fallback will be triggered when in sensor mode
	CLRI	hud_battery_mv				; clear battery voltage

	banksel	sensor1_mv					; select bank where sensor data are stored
	CLRI	sensor1_mv					; clear all sensor data
	CLRI	sensor2_mv					; ...
	CLRI	sensor3_mv					; ...
	clrf	sensor1_ppO2				; ...
	clrf	sensor2_ppO2				; ...
	clrf	sensor3_ppO2				; ...
	banksel	s8_rawdata_sensor1
	CLRI	s8_rawdata_sensor1			; clear all sensor data (raw data)
	clrf	s8_rawdata_sensor1+2
	CLRI	s8_rawdata_sensor2			; clear all sensor data (raw data)
	clrf	s8_rawdata_sensor2+2
	CLRI	s8_rawdata_sensor3			; clear all sensor data (raw data)
	clrf	s8_rawdata_sensor3+2
	banksel	isr_backup					; back to ISR default bank

	bsf		trigger_S8_data_update		; signal a data update

 ENDIF	; _external_sensor

isr_sensor_state2:
	btfss	sensor_state_counter,0				; every 1/4 second
	bsf		trigger_quarter_second				; set flag

	btfss	speed_is_normal						; 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) and 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

	; first, do state 2:
	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 for pressure
	bcf		STATUS,C							; clear carry bit
	rrcf	pressure_abs_avg+1					; divide by 2
	rrcf	pressure_abs_avg+0					; ...
	bcf		STATUS,C							; clear carry bit
	rrcf	pressure_abs_avg+1					; divide by 2, again
	rrcf	pressure_abs_avg+0					; ...

	; export averaged pressure
	MOVII	pressure_abs_avg,pressure_abs		; export result

	; build average for temperature
	bcf		STATUS,C							; clear carry bit by default
	btfsc	temperature_avg+1,7					; sign bit set?
	bsf		STATUS,C							; YES - copy sign bit to carry bit
	rrcf	temperature_avg+1					; divide signed temperature by 2
	rrcf	temperature_avg+0					; ...
	bcf		STATUS,C							; clear carry bit by default
	btfsc	temperature_avg+1,7					; sign bit set?
	bsf		STATUS,C							; YES - copy sign bit to carry bit
	rrcf	temperature_avg+1					; divide signed temperature by 2 again (by 4 in total now)
	rrcf	temperature_avg+0					; ...
	MOVII	temperature_avg,temperature_cur		; store final result

	; check for temperature change
	movf	temperature_cur+0,W					; get current temperature, low  byte
	cpfseq	temperature_last+0					; compare with last temperature, equal?
	bra		isr_sensor_state2_2					; NO - temperature has changed
	movf	temperature_cur+1,W					; get current temperature, high byte
	cpfseq	temperature_last+1					; compare with last temperature, equal?
	bra		isr_sensor_state2_2					; NO - temperature has changed
	bra		isr_sensor_state2_3					; YES to both - no change

isr_sensor_state2_2:
	MOVII	temperature_cur,temperature_last	; store current temperature as last temperature for next round
	bsf		trigger_temp_changed				; set flag for temperature change

isr_sensor_state2_3:
	; reset state counter
	clrf	sensor_state_counter				; reset state counter
	btfss	reset_max_pressure					; shall clear the max pressure?
	bra		isr_sensor_state2_3a				; NO  - continue with checking for pressure change
	bcf		reset_max_pressure					; YES - clear request flag
	CLRI	pressure_rel_max					;     - clear max. pressure

isr_sensor_state2_3a:
	; check for pressure change
	movf	pressure_abs+0,W					; get current pressure, low  byte
	cpfseq	pressure_abs_last+0					; compare with last pressure, equal?
	bra		isr_sensor_state2_4					; NO  - pressure has changed
	movf	pressure_abs+1,W					; YES - get current pressure, high byte
	cpfseq	pressure_abs_last+1					;     - compare with last pressure, equal?
	bra		isr_sensor_state2_4					;       NO  - pressure has changed
	bra		isr_sensor_state2_5					;       YES - no change

isr_sensor_state2_4:
	MOVII	pressure_abs,pressure_abs_last		; store current pressure as last pressure for next round
	bsf		trigger_pres_cur_changed			; signal a pressure change

isr_sensor_state2_5:
	; compute relative pressure
	movf	pressure_surf+0,W					; get surface pressure, low  byte
	subwf	pressure_abs+0,W					; WREG = pressure_abs - pressure_surf (low  byte)
	movwf	pressure_rel_cur+0					; store relative pressure, low  byte
	movf	pressure_surf+1,W					; get surface pressure, high byte
	subwfb	pressure_abs+1,W					; WREG = pressure_abs - pressure_surf (high byte)
	movwf	pressure_rel_cur+1					; store relative pressure, high byte
	btfss	STATUS,N							; relative pressure < 0 ?
	bra		isr_sensor_state2_6					; NO  - OK, keep result
	CLRI	pressure_rel_cur					; YES - set relative pressure to zero

isr_sensor_state2_6:
	; check for new max relative pressure
	movf	pressure_rel_cur+0,W				; get current relative pressure, low  byte
	subwf	pressure_rel_max+0,W				; WREG = pressure_rel_max - pressure_rel_cur (low  byte)
	movf	pressure_rel_cur+1,W				; get current relative pressure, high byte
	subwfb	pressure_rel_max+1,W				; WREG = pressure_rel_max - pressure_rel_cur (high byte)
	btfss	STATUS,N							; result < 0, i.e. new max rel pressure?
	bra		isr_sensor_state2_6a				; NO
	MOVII	pressure_rel_cur,pressure_rel_max	; YES - set new max rel pressure
	bsf		trigger_pres_max_changed			;     - signal a pressure max change

isr_sensor_state2_6a:

 IFDEF _min_depth_option
	; check if min/max pressures shall be reset
	btfss	reset_trip_pressure						; shall reset the resettable min/max pressures?
	bra		isr_sensor_state2_6b					; NO
	bcf		reset_trip_pressure						; YES - clear request flag
	CLRI	pressure_rel_max_trip					;     - set max pressure to zero
	SETI	pressure_rel_min_trip					;     - set min pressure to biggest value possible
isr_sensor_state2_6b:
	; check for new resettable max relative pressure
	movf	pressure_rel_cur+0,W					; get current relative pressure, low  byte
	subwf	pressure_rel_max_trip+0,W				; WREG = pressure_rel_max - pressure_rel_cur (low  byte)
	movf	pressure_rel_cur+1,W					; get current relative pressure, high byte
	subwfb	pressure_rel_max_trip+1,W				; WREG = pressure_rel_max - pressure_rel_cur (high byte)
	btfss	STATUS,N								; result < 0, i.e. new max rel pressure?
	bra		isr_sensor_state2_6c					; NO  - continue checking for min depth
	MOVII	pressure_rel_cur,pressure_rel_max_trip	; YES - set new max rel pressure
isr_sensor_state2_6c:
	; check for new resettable min relative pressure
	movf	pressure_rel_cur+0,W					; get current relative pressure, low  byte
	subwf	pressure_rel_min_trip+0,W				; WREG = pressure_rel_min - pressure_rel_cur (low  byte)
	movf	pressure_rel_cur+1,W					; get current relative pressure, high byte
	subwfb	pressure_rel_min_trip+1,W				; WREG = pressure_rel_min - pressure_rel_cur (high byte)
	btfss	STATUS,C								; result > 0, i.e. new min rel pressure?
	bra		sensor_int_state_exit					; NO  - done
	MOVII	pressure_rel_cur,pressure_rel_min_trip	; YES - set new min rel pressure
 ENDIF	; _min_depth_option
	bra		sensor_int_state_exit					; done

sensor_int_state1_plus_restart:
	CLRI	pressure_abs_avg			; clear average register for pressure
	CLRI	temperature_avg				; clear average register for temperature

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)

sensor_int_state_exit:
	bcf		PIR5,TMR7IF					; clear IRQ flag
	bsf		PIE5,TMR7IE					; re-enable IRQs by TMR7
	bra		isr_adjust_speed			; set/restore CPU speed and return


;-----------------------------------------------------------------------------
; Helper Function for Display Dimming
;
isr_dimm_tft:							; adjust until max_CCPR1L = CCPR1L
	btfsc	screen_type3				; screen type 3 ?
	return								; YES - ignore, no dimming function with screen type 3
	btfsc	tft_is_dimming				; is the display dimming?
	return								; YES - ignore
	movf	max_CCPR1L,W				; NO  - proceed
	cpfsgt	CCPR1L						;     - CCPR1L > max_CCPR1L ?
	bra		isr_dimm_tft2				;       NO  - dim up
	decf	CCPR1L,F					;       YES - dim down
	return								;           - done
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  - dim up slow
	movlw	.10							; YES - dim up faster (+10)
	addwf	CCPR1L,F					;     - add to dimming value
isr_dimm_tft3:
	incf	CCPR1L,F					;     - dim up (+1)
	return								;     - done


;-----------------------------------------------------------------------------
; RTC Interrupt (invoked every 0.5 Seconds)
;
isr_rtcc:
	bcf		PIR3,RTCCIF					; clear flag
	bsf		trigger_half_second			; set flag for a new 1/2 second has begun
	btfsc	reset_timebase				; shall reset the timebase?
	bra		isr_rtcc_1					; YES - warp to new full second
	btg		timebase_0sec				; NO  - toggle the 1/2 second timebase
	btfsc	timebase_0sec				;     - did it toggled 1 -> 0 ?
	return								;       NO - on half second, done

isr_rtcc_1:
	; new full second
	bsf		trigger_full_second			; set flag for a new 1/1 second has begun

	btfsc	block_rtc_access			; ISR suspended from accessing the RTC?
	bra		isr_rtcc_2					; YES

	banksel	RTCCFG						; RTC registers are outside access RAM
	bsf		RTCCFG,RTCPTR1
	bsf		RTCCFG,RTCPTR0
	banksel	isr_backup					; back to ISR default bank

	movff	RTCVALL,rtc_year			; read year    in BCD
	movff	RTCVALH,rtc_day				; dummy read
	movff	RTCVALL,rtc_day				; read day     in BCD
	movff	RTCVALH,rtc_month			; read month   in BCD
	movff	RTCVALL,rtc_hour			; read hour    in BCD
	movff	RTCVALH,rtc_secs			; dummy read
	movff	RTCVALL,rtc_secs			; read seconds in BCD
	movff	RTCVALH,rtc_mins			; read minutes in BCD

	; convert BCD to DEC and set registers
	movf	rtc_mins,W
	rcall	isr_rtcc_convert_BCD_DEC	; convert to decimal with result in WREG
	movwf	rtc_mins
	movf	rtc_secs,W
	rcall	isr_rtcc_convert_BCD_DEC	; convert to decimal with result in WREG
	movwf	rtc_secs
	movf	rtc_hour,W
	rcall	isr_rtcc_convert_BCD_DEC	; convert to decimal with result in WREG
	movwf	rtc_hour
	movf	rtc_month,W
	rcall	isr_rtcc_convert_BCD_DEC	; convert to decimal with result in WREG
	movwf	rtc_month
	movf	rtc_day,W
	rcall	isr_rtcc_convert_BCD_DEC	; convert to decimal with result in WREG
	movwf	rtc_day
	movf	rtc_year,W
	rcall	isr_rtcc_convert_BCD_DEC	; convert to decimal with result in WREG
	movwf	rtc_year

isr_rtcc_2:
	; every full second - get ambient light level and set max_CCPR1L
	call	get_ambient_level			; get ambient light level and set max_CCPR1L
	banksel	isr_backup					; back to ISR default bank (for safety only)

	rcall	isr_battery_gauge			; calculate the current charge consumption and add it to the battery gauge
	rcall	isr_update_uptime			; increment overall OSTC uptime
	rcall	isr_update_timeout			; process the timeout timer

	btfsc	divemode					; in dive mode?
	rcall	isr_divemode_1sec			; YES - do the every second dive mode tasks

	; increment surface interval counted in seconds
	btfsc	divemode					; in dive mode?
	btfsc	simulatormode				; YES - in simulator mode?
	rcall	inc_surface_interval_secs	; NO  - YES - increment the surface interval (seconds timer)

	; reset the surface interval timers if requested
	btfsc	reset_surface_interval		; shall reset both surface interval timers?
	rcall	rst_surface_interval		; YES

	; reset the timebase if requested
	btfss	reset_timebase				; shall reset the timebase?
	bra		isr_rtcc_3					; NO
	bcf		reset_timebase				; YES - clear request flag
	clrf	eventbase					;     - clear all pending events
	clrf	timebase					;     - clear all timebase flags
	clrf	timebase_secs				;     - clear seconds timer
	clrf	timebase_mins				;     - clear minutes timer
	clrf	simulator_time				;     - clear minutes timer of simulator runtime as well
	bsf		trigger_half_second			;     - set flag for a new 1/2 second has begun
	bsf		trigger_full_second			;     - set flag for a new 1/1 second has begun
	return								;     - done

isr_rtcc_3:
	; count-up the 2 seconds timebase timer
	btg		timebase_1sec				; toggle the 1 second timer bit
	btfss	timebase_1sec				; did it toggled 1 -> 0 ?
	btg		timebase_2sec				; YES - toggle the 2 seconds timer bit

	; count-up the seconds timer
	incf	timebase_secs,F				; increment seconds timer (may temporary become 60 here)
	movlw	.59							; max. for seconds timer
	cpfsgt	timebase_secs				; seconds timer > max.?
	return								; NO  - done

	; new full minute
	clrf	timebase_secs				; reset timer
	bsf		trigger_full_minute			; set flag for a new minute has begun

	; increment surface interval counted in minutes
	btfsc	divemode					; in dive mode?
	btfsc	simulatormode				; YES - in simulator mode?
	rcall	inc_surface_interval_mins	; NO  - YES - increment surface interval (minutes timer)

	btfss	simulatormode				; in simulator mode?
	bra		isr_rtcc_4					; NO
	infsnz	simulator_time,F			; YES - increment real runtime of the simulator, did wrap around (became zero)?
	setf	simulator_time				;       YES - disallow wrap-around, keep at 255 instead

isr_rtcc_4:
	incf	timebase_mins,F				; increment minutes timer
	movlw	.59							; max. for minutes timer
	cpfsgt	timebase_mins				; minutes timer > max.?
	return								; NO  - done

	; new full hour
	clrf	timebase_mins				; YES - reset timer
	bsf		trigger_full_hour			;     - set flag for a new hour has begun
	return								;     - done

	; increment overall OSTC uptime
isr_update_uptime:
	incf	uptime+0,F					; uptime++
	clrf	WREG						; ...
	addwfc	uptime+1,F					; ...
	addwfc	uptime+2,F					; ...
	addwfc	uptime+3,F					; ...
	return								; done

	; process the timeout timer
isr_update_timeout:
	btfsc	restart_timeout				; shall restart the timeout?
	bra		isr_update_timeout_1		; YES
	tstfsz	isr_timeout_timer			; NO  - timeout timer already at zero?
	decfsz	isr_timeout_timer,F			;       NO  - decrement timer, reached zero now?
	return								;       YES / NO  - nothing further to do
	bsf		trigger_timeout				;             YES - set timeout flag
	return								;                 - done
isr_update_timeout_1:
	bcf		restart_timeout							; clear request flag
	bcf		trigger_timeout							; clear pending timeout trigger, if any
	movff	isr_timeout_reload,isr_timeout_timer	; reload timer
	return											; done


;-----------------------------------------------------------------------------
; Calculate Charge drawn from the Battery
;
isr_battery_gauge:
	btfsc	block_battery_gauge			; access to battery gauge suspended?
	return								; YES - done
	MOVLI	current_sleepmode,isr_mpr	; NO  - default to sleep mode with 100ľA/3600 -> nAs
	btfss	sleepmode					;     - in sleep mode?
	rcall	isr_battery_gauge2			;       NO - compute current consumption into isr_lo and isr_hi
	movf	isr_mpr+0,W					;     - 48 bit add of isr_mpr:2 to battery_gauge:6
	addwf	battery_gauge+0,F			;     - ...
	movf	isr_mpr+1,W					;     - ...
	addwfc	battery_gauge+1,F			;     - ...
	clrf	WREG						;     - ...
	addwfc	battery_gauge+2,F			;     - ...
	addwfc	battery_gauge+3,F			;     - ...
	addwfc	battery_gauge+4,F			;     - ...
	addwfc	battery_gauge+5,F			;     - ...
	return								;     - done


;-----------------------------------------------------------------------------
; Helper Function - compute current Consumption
;
isr_battery_gauge2:
	; Set consumption rate in nAs (nano Ampere x seconds)
	; Example:
	; MOVLI  .55556,isr_mpr    ; 0.2 Ah / 3600 seconds per hour * 1e9s = nAs
	;
	; Remark: although all the constants are named current_xxxx, in reality they mean charge!

	; Calculate current consumption for LED backlight: 47*CCPR1L+272  (according to values in hwos.inc: 115*CCPR1L+216)
	movlw	.70								; screen type 3 has a fix backlight current slope
	btfss	screen_type3					; does the OSTC have a screen type 3 ?
	movf	CCPR1L,W						; NO - for screen types 0, 1 and 2 get the slope from CCPR1L
	mullw	current_backlight_multi			; multiply with backlight factor current_backlight_multi
	ADDLI	current_backlight_offset,PRODL	; add           backlight offset current_backlight_offset
	MOVII	PRODL,isr_mpr					; copy result to isr_mpr

	; add current for CPU and GPU
	; cpu_speed_state = ECO     3.10 mA ->  861 nAs
	;                 = NORMAL  5.50 mA -> 1528 nAs
	;                 = FASTEST 8.04 mA -> 2233 nAs
	btfss	speed_is_eco					; speed = eco ?
	bra		isr_battery_gauge3				; NO
	ADDLI	current_speed_eco,isr_mpr		; YES - add current_speed_eco to isr_mpr
	bra		isr_battery_gauge5
isr_battery_gauge3:
	btfss	speed_is_normal					; speed = normal?
	bra		isr_battery_gauge4				; NO
	ADDLI	current_speed_normal,isr_mpr	; YES - add current_speed_normal to isr_mpr
	bra		isr_battery_gauge5
isr_battery_gauge4:
	ADDLI	current_speed_fastest,isr_mpr	; speed is fastest, add current_speed_fastest to isr_mpr
isr_battery_gauge5:
	btfss	ir_power						; IR enabled?
	bra		isr_battery_gauge6				; NO
	ADDLI	current_ir_receiver,isr_mpr		; YES - add current_ir_receiver to isr_mpr
isr_battery_gauge6:
	btfss	compass_enabled					; compass active?
	bra		isr_battery_gauge7				; NO
	ADDLI	current_compass,isr_mpr			; YES - add current_compass to isr_mpr
isr_battery_gauge7:
	return									; done


;-----------------------------------------------------------------------------
; Every Second Tasks while in Dive Mode
;
isr_divemode_1sec:
	decfsz	sampling_timer,F			; decrement sampling timer, became zero?
	bra		isr_divemode_1sec_1			; NO
	bsf		trigger_sample_divedata		; YES - set trigger flag for sampling dive data
	movff	sampling_rate,sampling_timer;     - reload timer

isr_divemode_1sec_1:
	btfss	reset_timebase				; shall reset the timebase? (request flag will be cleared later)
	bra		isr_divemode_1sec_2			; NO
	CLRI	total_divetime_secs			; YES - reset total   dive time, seconds (2 byte)
	clrf	counted_divetime_secs		;     - reset counted dive time, seconds (1 byte)
	CLRI	counted_divetime_mins		;     - reset counted dive time, minutes (2 byte)
	clrf	apnoe_dive_secs				;     - reset apnoe   dive time, seconds (1 byte)
	clrf	apnoe_dive_mins				;     - reset apnoe   dive time, minutes (1 byte)
	bcf		apnoe_at_surface			;     - apnoe mode starts in submerged state
	return								;     - done

isr_divemode_1sec_2:
	INCI	total_divetime_secs			; increase total dive time       (regardless of start_dive_threshold)
	btfss	count_divetime				; shall the dive time be counted (regarding     start_dive_threshold)?
	bra		isr_divemode_1sec_4			; NO  - too shallow / apnoe at surface
	incf	counted_divetime_secs,F		; YES - increase dive time (displayed dive time)
	movlw	d'59'						;     - 60 seconds make a minute
	cpfsgt	counted_divetime_secs		;     - next full minute reached?
	bra		isr_divemode_1sec_3			;       NO  - continue
	clrf	counted_divetime_secs		;       YES - reset seconds to 0
	INCI	counted_divetime_mins		;           - increase dive minutes
	bsf		divetime_longer_1min		;           - set flag for dive time exceeding 1 minute
	;bra	isr_divemode_1sec_3			;           - continue

isr_divemode_1sec_3:					; submerged
	btfss	FLAG_apnoe_mode				; in apnoe mode?
	return								; NO  - done
	btfss	apnoe_at_surface			;     - been at surface before?
	bra		isr_divemode_1sec_3a		;       NO  - increment the dive time
	bcf		apnoe_at_surface			;       YES - a new dive has begun
	bsf		apnoe_new_dive				;           - signal a new dive has begun
	clrf	apnoe_surface_secs			;           - clear surface seconds
	clrf	apnoe_surface_mins			;           - clear surface minutes
	clrf	apnoe_dive_secs				;           - clear dive    seconds
	clrf	apnoe_dive_mins				;           - clear dive    minutes
	MOVII	pressure_rel_cur,pressure_rel_max ;     - reset max pressure to current pressure
	bsf		trigger_pres_max_changed	;           - signal a new maximum pressure
isr_divemode_1sec_3a:
	incf	apnoe_dive_secs,F			; increment dive time, seconds
	movlw	d'59'						; 60 seconds make a minute
	cpfsgt	apnoe_dive_secs				; next full minute reached?
	return								; NO  - done
	clrf	apnoe_dive_secs				; YES - reset seconds to 0
	incf	apnoe_dive_mins,F			;     - increment dive time, minutes
	return								;     - done

isr_divemode_1sec_4:					; at surface
	btfss	FLAG_apnoe_mode				; in apnoe mode?
	return								; NO  - done
	bsf		apnoe_at_surface			; YES - memorize been at the surface
	incf	apnoe_surface_secs,F		;     - increment surface time, seconds
	movlw	d'59'						;     - 60 seconds make a minute
	cpfsgt	apnoe_surface_secs			;     - next full minute reached?
	return								;       NO  - done
	clrf	apnoe_surface_secs			;       YES - reset seconds to 0
	incf	apnoe_surface_mins,F		;           - increment surface time, minutes
	return								;           - done


;-----------------------------------------------------------------------------
; Helper Function - BCD to Binary conversion
;
; Input   WREG = value in BCD
; Output  WREG = value in binary
;
isr_rtcc_convert_BCD_DEC:
	movwf	isr_lo						; copy BCD to isr_lo
	swapf	isr_lo, W					; create swapped copy in WREG
	andlw	0x0F						; keep only the tens
	rlncf	WREG, W						; WREG = 2 * tens
	subwf	isr_lo, F					; 16 * tens + ones - 2*tens
	subwf	isr_lo, F					; 14 * tens + ones - 2*tens
	subwf	isr_lo, W					; 12 * tens + ones - 2*tens
	return								; done


;-----------------------------------------------------------------------------
; Check Buttons
;
isr_switch_right:
	bcf		INTCON,INT0IE				; disable external interrupt 0
	
	btfsc	button_hold_down_allowed,A	; ignore for mechanical push buttons
	bra	isr_switch_right2
	btfsc	T4CON,TMR4ON					; Timer4 running?
	bra	timer4_restart					; Yes, restart
isr_switch_right2:
    
	btfss	flip_screen					; 180° flipped?
	bsf		switch_right				; NO  - set flag for right button
	btfsc	flip_screen					; 180° flipped?
	bsf		switch_left					; YES - set flag for left button
	bra		isr_switch_common			; continue with common part

isr_switch_left:
	bcf		INTCON3,INT1IE				; disable external interrupt 1

	btfsc	button_hold_down_allowed,A	; ignore for mechanical push buttons
	bra	isr_switch_left2
	btfsc	T4CON,TMR4ON					; Timer4 running?
	bra	timer4_restart					; Yes, restart
isr_switch_left2:
    
	btfss	flip_screen					; 180° flipped?
	bsf		switch_left					; NO  - set flag for left button
	btfsc	flip_screen					; 180° flipped?
	bsf		switch_right				; YES - set flag for right button
	;bra	isr_switch_common			; continue with common part

isr_switch_common:
	btfss	button_hold_down_allowed,A	; ignore for mechanical push buttons
	bsf 	T4CON,TMR4ON			; Start timer 4
    
	btfsc	tmr5_preemtion_allowed		; timer 5 preemption allowed?
	bsf		PIR5,TMR5IF					; YES - preempt timer 5
	movlw	TMR1H_VALUE_FIRST			; load timer 1 (in steps of 7.8125 ms)
	movwf	TMR1H						; ...
	clrf	TMR1L						; ...
	bsf		T1CON,TMR1ON				; start timer 1
	bcf		INTCON3,INT1IF				; clear ext. int 1 request
	bcf		INTCON,INT0IF				; clear ext. int 0 request
	return								; done


;-----------------------------------------------------------------------------
; Button hold-down Interrupt
;
timer1int:
	bcf		PIR1,TMR1IF					; clear timer 1 IRQ request
	bcf		INTCON,INT0IF				; clear ext. int 0 request
	bcf		INTCON3,INT1IF				; clear ext. int 1 request

	; 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 IRQ
	bsf		INTCON3,INT1IE				; enable INT1 IRQ
	return

timer1int_left:
	btfss	flip_screen					; 180° flipped?
	bsf		switch_left					; set flag for left button
	btfsc	flip_screen					; 180° flipped?
	bsf		switch_right				; set flag for right button
	bra		timer1int_common			; continue

timer1int_right:
	btfss	flip_screen					; 180° flipped?
	bsf		switch_right				; set flag for right button
	btfsc	flip_screen					; 180° flipped?
	bsf		switch_left					; set flag for left button
	;bra	timer1int_common			; continue

timer1int_common:						; load timer 1 for next button press
	movlw	TMR1H_VALUE_CONT			; default to surface mode value
	btfsc	divemode					; in dive mode?
	movlw	TMR1H_VALUE_CONT_DIVE		; YES - overwrite with dive mode value
	movwf	TMR1H						; write value to timer, high byte
	clrf	TMR1L						; write value to timer, low  byte (zero)
	return								; done (timer1 kept running)


;-----------------------------------------------------------------------------
; Increment Surface Interval (counted in minutes and in seconds)
;
; int_O_desaturation_time is only computed while in start, surface mode,
; menue_tree or ghostwriter. So the ISR may clock surface_interval_mins
; past the actual surface interval time. But TFT_surf_cv_lastdive will
; check int_O_desaturation_time and in case int_O_desaturation_time is
; zero it will not show surface_interval_mins but surface_interval_secs instead.
; Thus the glitch will remain invisible.
;
inc_surface_interval_secs:							; called every second when not in dive mode
	incf	surface_interval_secs+0,F				; increment the lowest byte
	clrf	WREG									; clear WREG
	addwfc	surface_interval_secs+1,F				; add carry from byte before, if it did wrap-around
	addwfc	surface_interval_secs+2,F				; add carry from byte before, if it did wrap-around
	addwfc	surface_interval_secs+3,F				; add carry from byte before, if it did wrap-around
	return											; done

inc_surface_interval_mins:							; called every minute when not in dive mode
	movff	int_O_desaturation_time+0,isr_lo		; get desaturation time, low  byte
	movff	int_O_desaturation_time+1,WREG			; get desaturation time, high byte
	iorwf	isr_lo,W								; inclusive-or low & high byte, desaturation time = 0 ?
	bz		clr_surface_interval_mins				; YES - reset surface interval minutes counter
	INCI	surface_interval_mins					; NO  - increment surface interval
	return											;     - done

rst_surface_interval:
	bcf		reset_surface_interval					; reset request flag
	; reset the surface interval counted in seconds
	clrf	surface_interval_secs+0					; reset surface interval (seconds), lowest  byte
	clrf	surface_interval_secs+1					; ...
	clrf	surface_interval_secs+2					; ...
	clrf	surface_interval_secs+3					; reset surface interval (seconds), highest byte
	; reset the surface interval counted in minutes
	movff	opt_diveTimeout,surface_interval_mins+0	; set   surface interval (minutes), low  byte, to dive timeout offset
	clrf	surface_interval_mins+1					; reset surface interval (minutes), high byte
	return											; done

clr_surface_interval_mins:
	clrf	surface_interval_mins+0					; reset surface interval (minutes), low byte
	clrf	surface_interval_mins+1					; reset surface interval (minutes), high byte
	return											; done

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

	END