Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Pic call from interrupt

Status
Not open for further replies.

ssaguiar

New Member
Hi to all.

I wish to know if it's possible (or even recomended or not), to make a call from inside an interrupt routine using pic microprocessors.
I was told that this is not a good practice, but I have seen a lot of codes which uses this.
For example, can I call a table routine, from a Timer0 or Timer1 interrupt, or a call to a beep or a keboard routine?

Thanks for your help.
 
On the 16 series chips it is not a good idea as the stack can only hold 8 addresses. If you use a call from your interrupt then your main code only has 6 levels left and that is quite limiting. On the 18 series chips this is not as much of a problem as the stack is 32 levels deep. Some C compilers get around the limit in a different way and so can have more than 8 nested calls.

Mike.
 
Thank you, Pommie, for your answer.
As I am using a 16F series processor, I will try to avoid using calls from interrupt vector.
In reality, I want to call a table to update displays during the interrupt.
 
Last edited:
My experience is with the 18F series and the C18 Microchip compiler. When you include a function call in the ISR, the compiler will add in a whole lot of additional code at the start and end of the ISR to setup/remove the function calling convention structures. This can add quite a few microseconds t the interrupt latency.

If timing is important (and presumably that i why you are using an ISR) then I would recommend against any function calls.

Susan
 
Thank you, Pommie, for your answer.
As I am using a 16F series processor, I will try to avoid using calls from interrupt vector.
In reality, I want to call a table to update displays during the interrupt.
There is a way to access a table without using a call,
Code:
DoTable		movwf	temp
		addwf	PCL,f
		xorlw	"H"^"e"
		xorlw	"e"^"l"
		xorlw	"l"^"l"
		xorlw	"l"^"o"
		xorlw	"o"^" "
		xorlw	" "^"W"
		xorlw	"W"^"o"
		xorlw	"o"^"r"
		xorlw	"r"^"l"
		xorlw	"l"^"d"
		xorlw	"d"^"!"
		xorlw	"!"
		xorwf	temp,w
		nop
After executing the above, W will contain the nth (value in W at the top) element of "Hello World!". So, if W contained 4 at the top of the code it will contain "o" at the bottom.

HTH

Mike.
 
Thanks Susan and Pommie, for your answers.

Pommie, I will try your solution, because, as I am treating the displays inside the interrupt isr (to mantain timming), I need the table to update the display's element.
There was another solution indicated which consists basically in updating the displays, leds and reading the keys inside the main loop, using timing routines, but this seemed not be working very well,so I am trying to use the interrupt.
Pommie, just another question:
How can I apply the code you posted to display's table?
Code:
DECDISP_A
	ADDWF   PCL,F		; compute the jump value
				;	|7|6|5|4|3|2|1|0| -	Bits PORTA
				;	|-|-|B|E|-|A|-|-|
	RETLW	B'00000000'	;	|-|-|B|E|-|A|-|-| -	0
	RETLW	B'00010100'	;	|-|-|B|X|-|X|-|-| -	1
	RETLW	B'00000000'	;	|-|-|B|E|-|A|-|-| -	2
	RETLW	B'00010000'	;	|-|-|B|X|-|A|-|-| -	3
	RETLW	B'00010100'	;	|-|-|B|X|-|X|-|-| -	4
	RETLW	B'00110000'	;	|-|-|X|X|-|A|-|-| -	5
	RETLW	B'00100000'	;	|-|-|X|E|-|A|-|-| -	6
	RETLW	B'00010000'	;	|-|-|B|X|-|A|-|-| -	7
	RETLW	B'00000000'	;	|-|-|B|E|-|A|-|-| -	8
	RETLW	B'00010000'	;	|-|-|B|X|-|A|-|-| -	9
	RETLW	B'11111111'	;	|C|F|D|G|-|-|-|-| -	BLANK

Sergio
 
Last edited:
You might check my PIC seven segment tutorial, which uses a single call from the ISR (to a table):



There's no problem with call's in ISR's, BUT you have to make absolutely certain that you don't overflow the stack as it's very small.

I don't see as one call is a problem, but don't use nested calls, and make a count of any nested calls in your main program - to give a margin of safety ensure you have a couple of stack levels left - and don't forget, the ISR itself is a stack call. It's also a good idea to try and keep ISR's as short as you can.
 
Thanks Nigel, for your answer.

This is the code I am using now:
Code:
	ORG		0x0000
	GOTO	set_up

	ORG 0x0004
	GOTO INTERRUPTS_ISR

Inside the Interrupt Isr:

Code:
INTERRUPTS_ISR
	; Save context:
	MOVWF   W_TEMP			; save off current W register contents
	MOVF	STATUS,w		; move status register into W register
	MOVWF	STATUS_TEMP		; save off contents of STATUS register
	MOVF	FSR,W			; Save FSR register
	MOVWF	FSR_TEMP		; to FSR_TEMP
	MOVF	PCLATH,w		; move pclath register into w register
	MOVWF	PCLATH_TEMP		; save off contents of PCLATH register

	CLRF	PCLATH			; Clear PCLATH
							; (Select PAGE 0)
	CLRF	STATUS			; Clear STATUS
							; (Select BANK 0)
	BTFSC	PIE1,TMR1IE		; Timer1 overflow interrupt?
	GOTO	INT_TMR1		; Yes.
	BTFSS	INTCON,T0IF		; Timer0 overflow interrupt?
	GOTO	END_INT			; No.

INT_TMR0

EXIT_TMR0_INT
	;BCF		INTCON,T0IF		; Clear TMR0 interrupt flag
	;GOTO	END_INT			; Exit interrupt

INT_TMR1
	BCF		PIR1,TMR1IF		; Clear Timer1 Interrupt flag
	MOVLW	0x30;0x18			;
	MOVWF	TMR1L			;
	MOVLW	0xF8;0xFC			;
	MOVWF	TMR1H			; Init TIMER1 with decimal 64536 (interrupt every 1ms)


	BSF		LED_CMN			; Leds OFF
	BSF		DISP3			; Display3 OFF
	BSF		DISP2			; Display2 OFF
	BSF		DISP1			; Display1 OFF
	CLRF	PORTA
	CLRF	PORTB

	BTFSS	LEDS_S,1		; Are we in temperature mode?
	GOTO	timermode		; No, we are in timer mode
	MOVF	TEMPER,W		; Put temperature in W
	;INCF	TEMPER,F
	CALL	bin2bcd			; Decode temperature to bcd
	GOTO	ll2				; continue
timermode:
	MOVF	TIMER,W			; Put time in W
	INCF	TIMER,F
	CALL	bin2bcd			; Decode time to bcd
ll2:

	INCF	INDEX_DISP,F	; Increment display index
	MOVLW	D'3'			; Limit counter from 0 to 3
	ANDWF	INDEX_DISP,F	;	"		"		"

	MOVLW	D'0'
	XORWF	INDEX_DISP,W	; If index = 0
	BTFSC	STATUS,Z		; Then it's time
	GOTO	SETLEDS			; to show LEDS
	MOVLW	D'1'
	XORWF	INDEX_DISP,W	; If index = 1
	BTFSC	STATUS,Z		; Then it's time
	GOTO	SETDISP3		; to show DISPLAY1
	MOVLW	D'2'
	XORWF	INDEX_DISP,W	; If index = 2
	BTFSC	STATUS,Z		; Then it's time
	GOTO	SETDISP2		; to show DISPLAY2
	MOVLW	D'3'
	XORWF	INDEX_DISP,W	; If index = 3
	BTFSC	STATUS,Z		; Then it's time
	GOTO	SETDISP1		; to show DISPLAY3

;Leds stuff
SETLEDS
    BCF		LED_UP			; Led UP always on
    BCF		LED_DWN			; Led DWN always on
    BTFSC	LEDS_S,3		; Is led light on?
    GOTO	$+3
    BSF		LED_LIGHT		; No
    GOTO	$+2
    BCF		LED_LIGHT		; Yes
    BTFSC	LEDS_S,2		; Is led toast on?
    GOTO	$+3
    BSF		LED_TOASTER		; No
    GOTO	$+2
    BCF		LED_TOASTER		; Yes
    BTFSC	LEDS_S,5		; Is led time on?
    GOTO	$+3
    BSF		LED_TIMER		; No
    GOTO	$+2
    BCF		LED_TIMER		; Yes
    BTFSC	LEDS_S,1		; Is led temp on?
    GOTO    $+3
    BSF		LED_TEMP		; No
    GOTO	$+2
    BCF		LED_TEMP		; YES
	BCF		LED_CMN			; Leds ON
	GOTO	$+1				; 2 us delay (transistor response time)
	GOTO	CONT_INT

SETDISP3
	MOVF	HUNDREDS,W		; Test to see if HUNDREDS
	XORLW	D'0'			; are zero (00) so
	BTFSC	STATUS,Z		; we turn display off
	GOTO	CONT_INT
	MOVF	HUNDREDS,W		; copy again hundeds to W (was cleared?)
	CALL	DECDISP_A		; convert
	MOVWF	PORTA			; put it in PORTA
	MOVF	HUNDREDS,W		; copy hundeds to W
	CALL	DECDISP_B		; convert
	MOVWF	PORTB			; put it in PORTB
	BCF		DISP3			; display 3 on
	GOTO	$+1				; 2 us delay (transistor response time)
	GOTO	CONT_INT

SETDISP2
	MOVF	HUNDREDS,W		; Test to see if HUNDREDS
	XORLW	D'0'			; are zero (00) so
	BTFSS	STATUS,Z		; if TENS are also 0, we turn it off.
	GOTO	CONTTENS

	MOVF	TENS,W			; If we get here, HUNDREDS are zero, so test to see if TENS also 0
	XORLW	D'0'			; Are TENS = 0?
	BTFSC	STATUS,Z		; Test it
	GOTO	CONT_INT		; Yes, let both HUNDREDS and TENS digits off!
CONTTENS
	MOVF	TENS,W			; copy tens to W
	CALL	DECDISP_A		; convert
	MOVWF	PORTA			; put it in PORTA
	MOVF	TENS,W			; copy tens to W
	CALL	DECDISP_B		; convert
	MOVWF	PORTB			; put it in PORTB
	BCF		DISP2			; display 2 on
	GOTO	$+1				; 2 us delay (transistor response time)
	GOTO	CONT_INT

SETDISP1
	MOVF	UNITS,W			; copy UNITS to W
	CALL	DECDISP_A		; convert
	MOVWF	PORTA			; put it in PORTA
	MOVF	UNITS,W			; copy UNITS to W
	CALL	DECDISP_B		; convert
	MOVWF	PORTB			; put it in PORTB
	BCF		DISP1			; display 1 on
	GOTO	$+1				; 2 us delay (transistor response time)
	GOTO	CONT_INT

CONT_INT

	INCF	TMR_1MS,F		; Increment TR_1MS (1 ms counter)

	MOVLW	D'100'
	XORWF	TMR_1MS,W		; Is TMR_1MS = 100?
	BTFSC	STATUS,Z		; No, skip if TMR_1MS < 100
	GOTO	INC100MS		; Yes, zero TMR_1MS and inc TMR_100MS
	GOTO	END_INT			; No, exit interrupt

INC100MS
	CLRF	TMR_1MS			; Zero TMR_1MS
	INCF	TMR_100MS,F		; Increment TMR_100MS (100 ms counter)
	MOVLW	D'4'			; 500 ms?
	XORWF	TMR_100MS,W		; Is TMR_100MS = 5 (500ms)?
	BTFSC	STATUS,Z		; No, skip if TMR_100MS < 5
	GOTO	INCCONTA		; Yes, zero TMR_100MS and inc 0,5 seconds counter
	GOTO	END_INT			; No, Exit interrupt

INCCONTA
	CLRF	TMR_100MS		; Zero 100 ms counter (reached 500ms)
    BTFSS	LEDS_S,7		; Is led blink enabled?
    GOTO	LEDOUT			; No, it's not enabled
	MOVLW	D'1'			; Verify if ...
	XORWF	T1_CONTA,W		; passed 1/2 second ...
	BTFSC	STATUS,Z		;
	GOTO	LEDON			; Led ONOFF is ON? Goto LEDON
LEDOFF
	BCF		LED_ONOFF		; Turn OFF LEDON_OFF
	GOTO	LEDOUT			; ok, done...
LEDON
	BSF		LED_ONOFF		; Turn ON LED_ONOFF
LEDOUT
	DECFSZ	T1_CONTA,F		; Decrement the Counter Register
	GOTO	END_INT			; If diferent of zero, exit interrupt
	MOVLW	2				;
	MOVWF	T1_CONTA		; Restart Counter Register with 2
	GOTO	END_INT

END_INT

and the 2 tables:
Code:
DECDISP_A
	ADDWF   PCL,F		; compute the jump value
						;	|7|6|5|4|3|2|1|0| -	Bits PORTA
						;	|-|-|B|E|-|A|-|-|
	RETLW	B'00000000'	;	|-|-|B|E|-|A|-|-| -	0
	RETLW	B'00010100'	;	|-|-|B|X|-|X|-|-| -	1
	RETLW	B'00000000'	;	|-|-|B|E|-|A|-|-| -	2
	RETLW	B'00010000'	;	|-|-|B|X|-|A|-|-| -	3
	RETLW	B'00010100'	;	|-|-|B|X|-|X|-|-| -	4
	RETLW	B'00110000'	;	|-|-|X|X|-|A|-|-| -	5
	RETLW	B'00100000'	;	|-|-|X|E|-|A|-|-| -	6
	RETLW	B'00010000'	;	|-|-|B|X|-|A|-|-| -	7
	RETLW	B'00000000'	;	|-|-|B|E|-|A|-|-| -	8
	RETLW	B'00010000'	;	|-|-|B|X|-|A|-|-| -	9
	RETLW	B'11111111'	;	|C|F|D|G|-|-|-|-| -	BLANK

;/****************************************************************************
;* DESCRIPTION: Decodes value in W register to display segments for PORTB.
;* return:      result in W
;* ALGORITHM:   none
;* NOTES:
;*****************************************************************************/ 
DECDISP_B
	ADDWF   PCL,F		; compute the jump value
						;	|7|6|5|4|3|2|1|0| -	Bits PORTB
						;	|C|F|D|G|-|-|-|-| -
	RETLW	B'00010000'	;	|C|F|D|X|-|-|-|-| -	0
	RETLW	B'01110000'	;	|C|X|X|X|-|-|-|-| -	1
	RETLW	B'11000000'	;	|X|X|D|G|-|-|-|-| -	2
	RETLW	B'01000000'	;	|C|X|D|G|-|-|-|-| -	3
	RETLW	B'00100000'	;	|C|F|X|G|-|-|-|-| -	4
	RETLW	B'00000000'	;	|C|F|D|G|-|-|-|-| -	5
	RETLW	B'00000000'	;	|C|F|D|G|-|-|-|-| -	6
	RETLW	B'01110000'	;	|C|X|X|X|-|-|-|-| -	7
	RETLW	B'00000000'	;	|C|F|D|G|-|-|-|-| -	8
	RETLW	B'00000000'	;	|C|F|D|G|-|-|-|-| -	9
	RETLW	B'11111111'	;	|C|F|D|G|-|-|-|-| -	BLANK
I need to use 2 tables because the display's segments are placed in the ports A and B.
 
Last edited:
I doesn't matter having two tables, as you don't nest the calls - so it's still only a single stack call.

However, your ISR seems a bit long, have you timed it?.

What about bin2bcd?, that's another call - and probably better done outside the ISR?.
 
Yes, the bin2bcd can be called from outside the isr.
Normally, I have done it in the main loop:
Code:
Main
	BTFSS	LEDS_S,1		; Are we in temperature mode?
	GOTO	timermode		; No, we are in timer mode
	MOVF	TEMPER,W		; Put temperature in W
	;INCF	TEMPER,F
	CALL	bin2bcd			; Decode temperature to bcd
	GOTO	ll2				; continue
timermode:
	MOVF	TIMER,W			; Put time in W
	INCF	TIMER,F
	CALL	bin2bcd			; Decode time to bcd
ll2:

	GOTO	Main			; Back to main loop
Using this, the start of the timer1 interrupt isr is:
Code:
	BSF		LED_CMN			; Leds OFF
	BSF		DISP3			; Display3 OFF
	BSF		DISP2			; Display2 OFF
	BSF		DISP1			; Display1 OFF
	CLRF	PORTA
	CLRF	PORTB


	INCF	INDEX_DISP,F	; Increment display index
	MOVLW	D'3'			; Limit counter from 0 to 3
	ANDWF	INDEX_DISP,F	;	"		"		"
And so on...
I am experimenting several problems with the timing, in the main loop.
If I put the keys in main loop, I get the leds and displays very dimm (I think this is the word - they have little bright).
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top