view code_part1/OSTC_code_asm_part1/isr.asm @ 341:2144f19fa1eb

BUGFIX protect against ISR changing pressure/temperature while reading it.
author JeanDo
date Fri, 20 May 2011 00:48:30 +0200
parents ecbbbd423e86
children d5240792be51
line wrap: on
line source


; OSTC - diving computer code
; Copyright (C) 2008 HeinrichsWeikamp GbR

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;    (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.


; written by: Matthias Heinrichs, info@heinrichsweikamp.com
; written: 10/30/05
; last updated: 05/16/08
; known bugs:
; ToDo:

; the timer1 module interrupts every 62.5ms (16x/second)
; temperature and pressure is averaged over 4 measurements
; flag pressure_refresh is set every 500ms 
; and provides accurate pressure (+/-1mBar stable) and temperature (0.1C stable)

;=============================================================================
; Copy a 16bit value from ISR modified registers to main registers.
; 
; Because the ISR can happend at any time, the read should be redone if bytes
; changed inbetween.
;
; NOTE: Destination might be in any bank, so be BANK SAFE on b

SAFE_2BYTE_COPY MACRO  a, b
        local   retry
retry:
        movf    a+1,W                   ; High byte in W, (CURRENT BANK ONLY)
        movff   WREG,b+1                ; and destination.
        movff   a,b                     ; Copy low byte.
        xorwf   a+1,W                   ; High byte changed ??? (CURRENT BANK ONLY)
        bnz     retry
        ENDM

;=============================================================================
uartint:
		btfsc	simulatormode_active		; are we in simulatormode?
		bra		simulator_int				; Yes, reading is depth in m!

		movff	RCREG,uart1_temp
		movlw	d'96'
		subwf	uart1_temp,F
		dcfsnz	uart1_temp,F				; "a"
		bsf		dump_external_eeprom		; set flag
		dcfsnz	uart1_temp,F				; "b"
		bsf		uart_settime				; set flag
		dcfsnz	uart1_temp,F				; "c"
		bsf		simulatormode_active		; set flag
		dcfsnz	uart1_temp,F				; "d"
		bsf		internal_eeprom_write		; set flag
		dcfsnz	uart1_temp,F				; "e"
		bsf		uart_send_hash				; set flag
		dcfsnz	uart1_temp,F				; "f"
		bsf		uart_reset_battery_stats	; set flag
		dcfsnz	uart1_temp,F				; "g"
		bsf		uart_send_int_eeprom		; set flag
		dcfsnz	uart1_temp,F				; "h"
		bsf		uart_reset_decodata			; set flag
		dcfsnz	uart1_temp,F				; "i"
		bsf		internal_eeprom_write2		; set flag
		dcfsnz	uart1_temp,F				; "j"
		bsf		uart_send_int_eeprom2		; set flag
		dcfsnz	uart1_temp,F				; "k"
		bsf		uart_store_tissue_data		; set flag

		movlw	0xC1
		cpfseq	RCREG						; 115200Baud Bootloader request?
		bra		uartint1					; No
		bsf		uart_115200_bootloader		; Yes, set Flag

uartint1:
		movf	RCREG,w						; unload RCREG in stand-alone simulator mode
		bcf		PIR1,RCIF					; Clear flag
		bcf		RCSTA,CREN					; Clear receiver status
		bsf		RCSTA,CREN
		return

simulator_int:
		btfsc	standalone_simulator		; ignore in standalone simulator mode
		bra		uartint1

		bsf		LED_blue
		tstfsz	RCREG						; =0x00?
		bra		simulator_int1				; No
		incf	RCREG,F						; Yes, so force RCREG=1

simulator_int1:
		movf	RCREG,w						; depth in m
		mullw	d'100'						; result will be mbar
		movff	PRODL,sim_pressure+0		; stored for pressure overwrite
		movff	PRODH,sim_pressure+1
		bra		uartint1					; exit uart int

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

switch_left_int:
		bcf		INTCON,INT0IF				; Clear flag

		btfsc	T0CON,TMR0ON				; Timer0 running?
		bra		timer0_restart				; Yes, restart

		; OSTC 2N has flipped screen and exchanged switches...
		movff	win_flags,WREG				; Get into Bank0
		btfss	WREG,0
		bsf		switch_left					; Set flag, button press is OK
		btfsc	WREG,0
		bsf		switch_right				; Set flag, button press is OK

		bsf		T0CON,TMR0ON				; Start Timer 0
		return


switch_right_int:
		bcf		INTCON3,INT1IF				; Clear flag

		btfsc	T0CON,TMR0ON				; Timer0 running?
		bra		timer0_restart				; Yes, restart

		; OSTC 2N has flipped screen and exchanged switches...
		movff	win_flags,WREG				; Get into Bank0
		btfsc	WREG,0
		bsf		switch_left					; Set flag, button press is OK
		btfss	WREG,0
		bsf		switch_right				; Set flag, button press is OK

		bsf		T0CON,TMR0ON				; Start Timer 0
		return

timer0_restart:
		bcf		INTCON,TMR0IF				; Clear flag
		clrf	T0CON						; Timer0
		clrf	TMR0H
		clrf	TMR0L
		bsf		T0CON,TMR0ON				; Start Timer 0
		return

timer0int:
		bcf		INTCON,TMR0IF				; Clear flag
		bcf		T0CON,TMR0ON				; Stop Timer 0
		clrf	TMR0H
		clrf	TMR0L
		return

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

timer1int:
		bcf		PIR1,TMR1IF					; Clear flag

timer1int_debug:
		bcf		LED_red						; LEDr off (For charge indicator)

		movlw	0x08						; Timer1 int after 62.5ms (=16/second)
		cpfslt	TMR1H						; Did we miss a 1/16 second?
		incf	timer1int_counter1,F		; Yes, add extra 1/16 second

		movlw	0x08						; Timer1 int after 62.5ms (=16/second)
		subwf	TMR1H,F			
	
		incf	timer1int_counter1,F		; Increase timer1 counter

		movlw	d'15'						; One second 16
		cpfsgt	timer1int_counter1			 
		bra		sensor_int_pre				; only pressure sensor
		rcall	RTCisr						; adjust time, then query pressure sensor

sensor_int_pre:
		btfsc	sleepmode					; In sleepmode?
		return								; Yes

; Sensor interput do poll the presure/temperature sensor, download results,
; compute compensations, and store results in various shared variables.
;
; Input:    interupt (every 62.5msec == 16Hz), sensor,
;           last_surfpressure:2.
;
; Output:   amb_pressure:2,
;           temperature:2,
;           rel_pressure:2,
;           and the pressure_refresh flag.
;
; NOTE: averaging (4 successive value, as recommended in the MS5535 datasheet)
;       is done on private variables, to avoid trashing data while reading it
;       from the main code.
;
; NOTE: Because there is no atomic 16bits load/stores, we need to check twice
;       the read data is correct. Ie. SAFE_2BYTE_COPY is mandatory to get
;       amb_pressure, temperaturen or rel_pressure
;
sensor_int:
		btfsc		no_sensor_int			; No sensor interrupt (because it's addressed during sleep)
		return						

		incf		timer1int_counter2,F	; counts to eight for state maschine

; State 1: Clear flags and average registers, get temperature (51us) and start pressure integration (73,5us)
; State 2: Get pressure (51us), start temperature integration (73,5us) and calculate temperature compensated pressure (233us)
; State 3: Get temperature (51us) and start pressure integration (73,5us)
; State 4: Get pressure (51us), start temperature integration (73,5us) and calculate temperature compensated pressure (233us)
; State 5: Get temperature (51us) and start pressure integration (73,5us)
; State 6: Get pressure (51us), start temperature integration (73,5us) and calculate temperature compensated pressure (233us)
; State 7: Get temperature (51us) and start pressure integration (73,5us)
; State 8: Get pressure (51us), start temperature integration (73,5us), calculate temperature compensated pressure (233us) and build average for half-second update of tempperature and pressure
	
		movff	timer1int_counter2,isr_divB		; isr_divB used as temp here...
		dcfsnz	isr_divB,F
		bra		sensor_int_state1_plus_restart	; Do State 1
		dcfsnz	isr_divB,F
		bra		sensor_int_state2				; Do State 2
		dcfsnz	isr_divB,F
		bra		sensor_int_state1				; Do State 3
		dcfsnz	isr_divB,F
		bra		sensor_int_state2				; Do State 4
		dcfsnz	isr_divB,F
		bra		sensor_int_state1				; Do State 5
		dcfsnz	isr_divB,F
		bra		sensor_int_state2				; Do State 6
		dcfsnz	isr_divB,F
		bra		sensor_int_state1				; Do State 7
;		bra		sensor_int2_plus_average		; Do State 8

;sensor_int2_plus_average:
		rcall		sensor_int_state2
sensor_int2_plus_average2:		
		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
		movff		temperature_avg+0,temperature+0

		bsf			pressure_refresh 			; Set flag! Temp and pressure were updated!
		clrf		timer1int_counter2			; Then reset State counter

		btfss		simulatormode_active		; are we in simulator mode?
		bra			comp_air_pressure			; no

comp_air_pressure0:	
		movlw		LOW		d'1000'				; yes, so simulate 1Bar surface pressure
		movwf		last_surfpressure+0
		movlw		HIGH	d'1000'
		movwf		last_surfpressure+1

comp_air_pressure:
		movf		last_surfpressure+0,W		; compensate airpressure
		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					; result is below zero?
		return
		clrf		rel_pressure+0				; Yes, do not display negative depths
		clrf		rel_pressure+1				; e.g. when surface air pressure dropped during the dive
		return

sensor_int_state1_plus_restart:
;;;		bcf			pressure_refresh    ; clear flags
		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.
		return								; Done.

sensor_int_state2:
		call		get_pressure_value		; State2: Get pressure (51us)
		call		get_temperature_start	; and start temperature integration (73,5us)
		goto		calculate_compensation	; calculate temperature compensated pressure (233us)

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

RTCisr:			
		clrf		timer1int_counter1		; counts to 16 (one second / 62.5ms)
		bsf			onesecupdate			; we have a new second!

		bcf			STATUS,Z				; are we in dive mode?
		btfss		divemode
		bra			RTCisr2					; No, must be surface or sleepmode

		incf		samplesecs,F			; CF20 diving seconds done 
		decf		samplesecs_value,W		; holds CF20 value  (minus 1 into WREG)
		cpfsgt		samplesecs
		bra			RTCisr1					; no

		clrf		samplesecs				; clear counter...
		bsf			store_sample			; ...and set bit for profile storage

RTCisr1:		
; Increase re-setable average depth divetime counter
		incf		average_divesecs+0,F	; increase stopwatch registers	
		btfsc		STATUS,Z
		incf		average_divesecs+1,F	; increase stopwatch registers	

		btfss		divemode2				; displayed divetime is running?
		bra			RTCisr2					; No (e.g. too shallow)

		incf		divesecs,F				; increase divetime registers
		movlw		d'59'
		cpfsgt		divesecs
		bra			RTCisr1a

		clrf		divesecs
		bsf			realdive				; this bit is always set (again) if the dive is longer then one minute

		incf		divemins+0,F			; increase divemins
		btfsc		STATUS,Z
		incf		divemins+1,F			; and now do the realtime clock routine anyway
		
RTCisr1a:	
		btfss		FLAG_apnoe_mode			; Are we in Apnoe mode?
		bra			RTCisr2					; No, skip the following
		
		incf		apnoe_secs,F			; increase descent registers
		movlw		d'59'
		cpfsgt		apnoe_secs
		bra			RTCisr2
		clrf		apnoe_secs
		
		incf		apnoe_mins,F			; increase descent mins
		; Now, do the RTC routine....
RTCisr2:
		incf		secs,F					; adjusts seconds, minutes, hours, day, month and year. Checks for a leap year and works until 2099!
		movlw		d'59'
		cpfsgt		secs
		return
		clrf		secs
		bsf			oneminupdate
		incf		mins,F
		movlw		d'59'
		cpfsgt		mins
		return
		clrf		mins
		incf		hours,F
		movlw		d'23'
		cpfsgt		hours
		return
		clrf		hours
		incf		day,F
		movff		time_correction_value,secs			; Correct too slow clock
						
check_date:
		movff		month,isr_divB		; new month?
		dcfsnz		isr_divB,F
		movlw		.31
		dcfsnz		isr_divB,F
		movlw		.28
		dcfsnz		isr_divB,F
		movlw		.31
		dcfsnz		isr_divB,F
		movlw		.30
		dcfsnz		isr_divB,F
		movlw		.31
		dcfsnz		isr_divB,F
		movlw		.30
		dcfsnz		isr_divB,F
		movlw		.31
		dcfsnz		isr_divB,F
		movlw		.31
		dcfsnz		isr_divB,F
		movlw		.30
		dcfsnz		isr_divB,F
		movlw		.31
		dcfsnz		isr_divB,F
		movlw		.30
		dcfsnz		isr_divB,F
		movlw		.31
		cpfsgt		day,1
		return
		movlw		.1
		movwf		day
		incf		month,F				
		movlw		.12					
		cpfsgt		month,1
		return
		movlw		.1
		movwf		month
		incf		year,F				
		return