• 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.

strange 16f877a INT problem

Status
Not open for further replies.

dsc

Member
Hi guys,

I'm debugging a code for a 16f877a PIC chip and I can't force the damn thing to interrupt when I want it to.

Before starting the interrupts and going to a wait-until-off-switch-pressed loop I do the following:

Code:
movlw	b'00000100'		;set prescale 1:1
movwf	T1CON		

bcf	T1CON, 0		;turn off timer
movlw	b'11011011'		;lower byte to TMR1L
movwf	TMR1L			
movlw	b'00001011'		;high byte to TMR1H
movwf	TMR1H		;those two bytes write 3035 into the timer
	
bcf	PIR1, 0			;reset int flag
bsf	INTCON, 6		;enable all unmasked ints
bsf	INTCON, 7		;turn on global interrupts 
bsf	T1CON, 0		;turn on timer		

bsf 	STATUS,	RP0		;select bank 1
bsf 	PIE1, 0			;enable timer1 interrupts
bcf 	STATUS,	RP0		;select bank 0
This sets the TMR1 and preloads it with 3035 so that the interrupt happens every 62500us (4Mhz XTAL used). Afterwards the program goes into a loop where it simply waits until the right button is switched. Of course during the time spent in the loop the interrupts should execute every 62500us doing the following:

Code:
org	0x0004

		goto	Int_Serv			;interrupt service

Code:
Int_Serv
		
;====TEST ONLY====
bsf	PORTD, 7		;indication of the mode state for test purposes
;=================

;store regs for INT return

movwf 	w_temp 		;copy w to temp register
swapf 	STATUS,W 	;swap status to be saved into w
clrf 	STATUS 		;bank 0, regardless of current bank, clears irp,rp1,rp0
movwf 	s_temp 		;save status to bank zero s_temp register
movf 	PCLATH, W 	;only required if using pages 1, 2 and/or 3
movwf 	p_temp 		;save PCLATH into w
clrf 	PCLATH 		;page zero, regardless of current page


;always overwrite timer value as it has to run 8 x 62500us

bcf	T1CON, 0		;turn off timer
movlw	b'11011011'		;lower byte to TMR1L
movwf	TMR1L			
movlw	b'00001011'		;high byte to TMR1H
movwf	TMR1H		;those two bytes write 3035 into the timer
bsf	T1CON, 0		;turn on timer

(INT routine code)
		

bcf	PIR1, 0			;reset int flag
		
;restore saved reg values

movf 	p_temp, W 	;restore PCLATH
movwf 	PCLATH 		;move w into PCLATH
swapf 	s_temp,W 	;swap s_temp register into w
;(sets bank to original state)
movwf 	STATUS 		;move w into STATUS register
swapf 	w_temp,F 	;swap w_temp
swapf 	w_temp,W 	;swap w_temp into w

retfie
You can see that there's a TEST ONLY section at the beginning of the INT routine which is there to see whether the INT happens or not. As you can guess it doesn't and the LED hooked up to PORTD, 7 never lights up.

Now I've tested the TMR1IF flag simply to see whether it overflows at all, and it does. With this code in the loop where it waits for the switch-off (after the INTs are turned on):

Code:
btfsc	PIR1, TMR1IF
bsf		PORTD, 7
the LED lights up proving that the TMR1 counts up and actually overflows.

Has anyone got any ideas why the PIC can't see this flag or why it chooses to ignore it even though PIE1 bit 0 is set (TMR1 interrupt enable bit)? The PIC simply doesn't do the interrupts and everything else works fine, it doesn't freeze or get stuck.

I'd appreciate any feedback.

Regards,
dsc.
 

testerplus

New Member
Code:
org	0x0004
	goto	Int_Serv			;interrupt service
Here is an error. I' m not quite sure that it is a reason of of your problem, but there can be a problem. After any interrupt occures program counter points to address 0x0004, but PCLATH can contain a value diferent that you need t jump at Int_Serv. You must save context first (W, STATUS, PCLAHT), then set PCLATH, after that you can execute GOTO instruction.
 

Hayato

Member
actually the problem is using GOTO with RETFIE.

CALL pushes the PCLATH+1 to the stack. Then the RETFIE pops.

But he used GOTO, when the programs executes the RETFIE, what will be popped to the PCLATH?
Somethin undefined, or you'll have a stack overflow related issue.
 

dsc

Member
re

Hi guys,

I removed the goto instruction from before the INT routine and now it looks like this:

Code:
org	0x0004

Int_Serv
		
;====TEST ONLY====
bsf	PORTD, 7		;indication of the mode state for test purposes
;=================

;store regs for INT return

movwf 	w_temp 		;copy w to temp register
swapf 	STATUS,W 	;swap status to be saved into w
clrf 	STATUS 		;bank 0, regardless of current bank, clears irp,rp1,rp0
movwf 	s_temp 		;save status to bank zero s_temp register
movf 	PCLATH, W 	;only require

...
It doesn't work anyway, and because the LED connected to PORTD, 7 doesn't light up it looks like the INT routine isn't even started.

The main routine has a bunch of stuff in it, too big to cut and paste as the whole program has 1200 lines of code.

Regards,
dsc.

EDIT: I forgot to add that the whole program works normally under Oshon PIC simulator, including interrupts.
 
Last edited:

Nigel Goodwin

Super Moderator
Most Helpful Member
actually the problem is using GOTO with RETFIE.

CALL pushes the PCLATH+1 to the stack. Then the RETFIE pops.

But he used GOTO, when the programs executes the RETFIE, what will be popped to the PCLATH?
Somethin undefined, or you'll have a stack overflow related issue.
Using GOTO is perfectly fine, the return address isn't changed at all by it, so the RETFIE executes correctly.
 

dsc

Member
Hi guys,

I can't remove the RETFIE as it's needed to return from the INT routine. The GOTO wasn't a problem as it looks like the PIC isn't even going into the 0x0004 vector.

I've run it with Oshon simulator and it works fine, I will try to debug it wih MPlab. Is it possible to set the hardware inputs of the PIC in MPLab SIM? The circuit has around 8 inputs and I need to simulate their states somehow.

It can't be a LED problem as the LED works properly and the only thing the INT routine does is turn it on. It doesn't even turn it off, so once it lights up it should stay on constantly. At the moment it's off all the time.

Regards,
dsc.
 

testerplus

New Member
Hi guys,

Code:
org	0x0004
Int_Serv
		
;====TEST ONLY====
bsf	PORTD, 7		;indication of the mode state for test purposes
;=================

;store regs for INT return

movwf 	w_temp 		;copy w to temp register
swapf 	STATUS,W 	;swap status to be saved into w
clrf 	STATUS 		;bank 0, regardless of current bank, clears irp,rp1,rp0
movwf 	s_temp 		;save status to bank zero s_temp register
movf 	PCLATH, W 	;only require

...
Are you sure that on the moment of enterring interrupt RP0 and RP1 are both cleared? Once you enter interrupt with RP1=1, you set pin PORTD,7 as input (because TRISD,7 will be set instead of PORD,7). After pin set sa input it will never became "1".
 

dsc

Member
re

Hi guys,

when the interrupts are active the program cycles in a small loop:

Code:
Test_label
		
btfsc	PORTA, 2
goto	Test_label
(this is for test purposes only anyway)

so as you can see it's always in Bank0, both RP0 and RP1 are 0 all the time.

I've just finished debugging the code with MPLAB Sim and the interrupts work flawlessly in there:O is it possible that the INTs are somehow turned off via hardware, during programming the chip? I'm using ICPROG btw.

Regards,
dsc.
 

dsc

Member
Hi guys,

finally got it working:) it was the DEBUGGING fuse that was screwing things up. I've now got the correct config word set and it works well.

Thanks for all the replies!

Regards,
dsc.
 
Last edited:

Sceadwian

Banned
I think that's the third time I've seen someone have that problem in the last two weeks, if not more.
 

dsc

Member
re

Hi guys,

I'm still debugging the same code (now even bigger) and I've stumbled upon something strange. Recently I've added a 10k pot to the circuit and some ADC code to control a valve (via a stepper motor). The setting of the pot is changed to a 0-1023 value, then divided by 16 (ignoring the 4 LSBs) and the result is compared to the actual position of the valve. If it's bigger the valve is opened more, if it's smaller the valve is closed. So the pot is there to give 'manual' control and kind of simulate the valve (moving the pot moves the valve). In addition to this functionality there's also something called 'programming mode' which is used to sample the position of the valve. This is done via interrupts, every 0.5s the current setting of the valve is saved into memory (max 60 values are possible, 30s time period).

Now I had some debugging code in the chip which was turning a LED on when the interrupts went off. This was a simple command:

bsf PORTD, 7

inside the interrupt code and it was working fine before I added the pot. Now it 'sort of' works, but behaves kind of strange. When I turn the interrupts on and don't touch the pot the LED usually stays on all the time. When I start turning the pot one of the following happens:

- the LED goes off and doesn't go back on again
- the LED stays on for a few seconds but playing with the pot constantly makes it go off
- on some occasions the LED turns itself off even if I don't touch the pot, sometimes immediately after turning on the INTs and sometimes after a while

This is weird because the bsf command inside the interrupt routine should turn the LED on again during the next interrupt but that never happens and I haven't got any bcf commands for that pin anywhere in the code. After the LED goes off it doesn't want to go on again, I have to reset the PIC to get it working.

The funny bit is that the interrupts seem to be working properly. I can say that because the 60 values that are saved into memory during the interrupts can also be saved into EEPROM so I can have a look at them. So for example if I turn on the INTs, start playing with the pot, the LED goes off and I keep playing with the pot the pot positions are properly saved into the memory.

Does anyone know what might be going on? I tried using the PORTD, 7 pin for something else and it works without any problems. It seems that it's the INTs that are somehow screwing things up (at least the LED control).

Regards,
dsc.
 

Pommie

Well-Known Member
Most Helpful Member
Do you have a current limiting resistor on the LED. If you don't then any bsf/bcf on port D will clear the bit. This is because the pin is overloaded and any read of the port will read that bit as a zero and subsequently write it back.

Mike.
 

dsc

Member
re

Hi,

thanks for the response.

Yeah I've got a 220ohm resistor on that LED port, so that shouldn't be a problem. I've also got a bunch of other LEDs on that PORTD and they all work fine, it's just the LED that's turned on by the INT that's behaving strange.

Regards,
dsc.
 
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top