My application uses a rotary encoder on PORTB. Whenever the encoder is moved, an INT interrupt occurs, and the encoder state is read in the interrupt handler. There are also other interrupts running (timers). I'm not having problems with the timer interrupts, but I am having substantial problems with the system crashing when the encoder is turned. I finally trimmed my program down to some test code that illustrates the offending part:
#chip 16F877A, 20
#define LCD_IO 4
#define LCD_RS PORTD.3
#define LCD_Enable PORTD.2
#define LCD_NO_RW 1
#define LCD_DB4 PORTD.4
#define LCD_DB5 PORTD.5
#define LCD_DB6 PORTD.6
#define LCD_DB7 PORTD.7
On Interrupt ExtInt0 Call EncoderInterrupt 'enable encoder interrupts
set option_reg.7 off 'enable PortB pullups
dir portb.5 in 'encoder connected here; pulls low and interrupts on rotation
dir portb.6 in 'encoder connected here; pulls low and interrupts on rotation
set OPTION_REG.6 off 'interrupts on negative edges
SET INTCON.RBIE OFF 'disable other PORTB change interrupts
k=0
locate 0,0
Print "Program Started" 'LCD output
wait 1 s
'Wait in loop, counting and displaying encoder interrupts
loop:
cls
locate 0,0
Print k
Wait 200 ms
goto loop
'Encoder Interrupts
sub EncoderInterrupt
k = k+1
end sub
Even with this simple code which just increments and displays a variable , the program seems to crash regularly when the encoder is turned. Interestingly, the longer the processor is allowed to run before the encoder is turned, the less likely it is to crash. After about 10 seconds of run-time, it runs pretty reliably.
Personally, i'm suspicious of how GCB handles the context save (why is PCLATH just cleared instead of saved and restored?), and I'm also suspicious about whether bank pointers are always pointing to the right bank. But these are just suspicions.
Does anyone have any insight on this?
Joe
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
After a LOT of experimenting, I'm pretty sure of the cause if this problem. It seems that GCB's WAIT routines don't take kindly to this interrupt. If I disable/enable INT interrupts (SET INTCON.INTE OFF/ON) before and after any explicit WAIT instruction, as well as before/after any GCB instruction that calls internal WAIT routines, the problem seems to pretty much stop.
This problem is especially pronounced in tight loops, like the one cited above, that use LCD functions. It seems like practically every LCD function uses internal WAIT routines.
BTW, I'm using the latest GCB build as of this morning.
Has anyone else seen this?
Joe
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
After a LOT of experimenting, I'm pretty sure of the cause if this problem. It seems that GCB's WAIT routines don't take kindly to this interrupt. If I disable/enable INT interrupts (SET INTCON.INTE OFF/ON) before and after any explicit WAIT instruction, as well as before/after any GCB instruction that calls internal WAIT routines, the problem seems to pretty much stop.
This problem is especially pronounced in tight loops, like the one cited above, that use LCD functions. It seems like practically every LCD function uses internal WAIT routines.
BTW, I'm using the latest GCB build as of this morning.
Has anyone else seen this?
Joe
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Still having problems, but noticed that in the assembly source there are some address conflicts; ie, two variables assigned to the same address. Why???
Not sure about what could be the problem, but any interrupt will interfere in wait or any other routine that is being executed in that moment.
Lcd timings are afected for interrupts... have you tried printing to lcd inside interrupt?
Anyway in the code of your first post, you are using the wrong interrupt or the wrong pin: ExtInt0 (INTCON.INTE) interrupt is for PORTB.0, and PORTBChange (INTCON.RBIE) interrupt is for PORTB.4-7.
You are using ExtInt0 but encoder are atached to PORTB.5 and 6.
To know if the program is really crashing you could blink a led in the main loop as you already have a 200ms delay, just toggle led every loop cycle.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Good catch on my RB0 mistake, but that's not the problem. My encoder really is connected to RB0 for the INT interrupt (and RB6 for the other input); I just specified the incorrect port in the DIR spec. I fixed that error, but the program still crashes. It's not just that the interrupt affects the timing of things that use internal delay routines, it's an outright crash, or sometimes a restart.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok... i see one problem.
Your code uses strings, that are located at higher Bank, then uses PCLATH, and with last update GcBasic should save PCLATH or NOT clear it, but what it does is not saving PCLATH but clearing it (have a look to asm interrupt), I think program will crash for sure.
Then if PCLATH saving is no needed in interrupts, it should not be cleared.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It was the PCLATH clearing causing the problem. The string reading routines set PCLATH, then PCL, in order to read a character of a string from the program memory. If the interrupt occurred in the middle of reading a string, then PCLATH would be cleared, and when PCL was set the PIC would jump to a random location somewhere in the first 256 words of the program.
I've uploaded yet another update, which shouldn't clear PCLATH unless it's used in the interrupt, and that should then save PCLATH properly if it is.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
My application uses a rotary encoder on PORTB. Whenever the encoder is moved, an INT interrupt occurs, and the encoder state is read in the interrupt handler. There are also other interrupts running (timers). I'm not having problems with the timer interrupts, but I am having substantial problems with the system crashing when the encoder is turned. I finally trimmed my program down to some test code that illustrates the offending part:
#chip 16F877A, 20
#define LCD_IO 4
#define LCD_RS PORTD.3
#define LCD_Enable PORTD.2
#define LCD_NO_RW 1
#define LCD_DB4 PORTD.4
#define LCD_DB5 PORTD.5
#define LCD_DB6 PORTD.6
#define LCD_DB7 PORTD.7
On Interrupt ExtInt0 Call EncoderInterrupt 'enable encoder interrupts
set option_reg.7 off 'enable PortB pullups
dir portb.5 in 'encoder connected here; pulls low and interrupts on rotation
dir portb.6 in 'encoder connected here; pulls low and interrupts on rotation
set OPTION_REG.6 off 'interrupts on negative edges
SET INTCON.RBIE OFF 'disable other PORTB change interrupts
k=0
locate 0,0
Print "Program Started" 'LCD output
wait 1 s
'Wait in loop, counting and displaying encoder interrupts
loop:
cls
locate 0,0
Print k
Wait 200 ms
goto loop
'Encoder Interrupts
sub EncoderInterrupt
k = k+1
end sub
Even with this simple code which just increments and displays a variable , the program seems to crash regularly when the encoder is turned. Interestingly, the longer the processor is allowed to run before the encoder is turned, the less likely it is to crash. After about 10 seconds of run-time, it runs pretty reliably.
Personally, i'm suspicious of how GCB handles the context save (why is PCLATH just cleared instead of saved and restored?), and I'm also suspicious about whether bank pointers are always pointing to the right bank. But these are just suspicions.
Does anyone have any insight on this?
Joe
Look at the suggestions in the other thread:
http://sourceforge.net/forum/forum.php?thread_id=3354519&forum_id=579126
Random crashes sounds like a missing clrf STATUS as mentioned above.
After a LOT of experimenting, I'm pretty sure of the cause if this problem. It seems that GCB's WAIT routines don't take kindly to this interrupt. If I disable/enable INT interrupts (SET INTCON.INTE OFF/ON) before and after any explicit WAIT instruction, as well as before/after any GCB instruction that calls internal WAIT routines, the problem seems to pretty much stop.
This problem is especially pronounced in tight loops, like the one cited above, that use LCD functions. It seems like practically every LCD function uses internal WAIT routines.
BTW, I'm using the latest GCB build as of this morning.
Has anyone else seen this?
Joe
After a LOT of experimenting, I'm pretty sure of the cause if this problem. It seems that GCB's WAIT routines don't take kindly to this interrupt. If I disable/enable INT interrupts (SET INTCON.INTE OFF/ON) before and after any explicit WAIT instruction, as well as before/after any GCB instruction that calls internal WAIT routines, the problem seems to pretty much stop.
This problem is especially pronounced in tight loops, like the one cited above, that use LCD functions. It seems like practically every LCD function uses internal WAIT routines.
BTW, I'm using the latest GCB build as of this morning.
Has anyone else seen this?
Joe
Still having problems, but noticed that in the assembly source there are some address conflicts; ie, two variables assigned to the same address. Why???
;Set aside memory locations for variables
DELAYTEMP EQU 112
DELAYTEMP2 EQU 113
SYSCALCTEMPX EQU 112
SYSDIVLOOP EQU 116
SYSSTRINGLENGTH EQU 118
SysCalcTempA EQU 117
SysCalcTempB EQU 121
SysSTATUS EQU 127
SysStringA EQU 119
SysStringA_H EQU 120
SysStringB EQU 114
SysStringB_H EQU 115
SysW EQU 126
SysWaitTemp10MS EQU 116
SysWaitTemp10US EQU 117
SysWaitTempMS EQU 114
SysWaitTempMS_H EQU 115
SYSSTRINGPARAM1 EQU 453
ENCINT EQU 32
K EQU 33
LCDBYTE EQU 34
LCDCOLUMN EQU 35
LCDLINE EQU 36
LCDREADY EQU 37
LCDVALUE EQU 38
LCDVALUETEMP EQU 39
PRINTLEN EQU 40
SYSPRINTTEMP EQU 41
StringPointer EQU 42
SysIFTemp EQU 43
SysIntOffCount EQU 44
SysPRINTDATAHandler EQU 45
SysPRINTDATAHandler_H EQU 46
SysTemp1 EQU 47
SysTemp2 EQU 48
Not sure about what could be the problem, but any interrupt will interfere in wait or any other routine that is being executed in that moment.
Lcd timings are afected for interrupts... have you tried printing to lcd inside interrupt?
Anyway in the code of your first post, you are using the wrong interrupt or the wrong pin: ExtInt0 (INTCON.INTE) interrupt is for PORTB.0, and PORTBChange (INTCON.RBIE) interrupt is for PORTB.4-7.
You are using ExtInt0 but encoder are atached to PORTB.5 and 6.
To know if the program is really crashing you could blink a led in the main loop as you already have a 200ms delay, just toggle led every loop cycle.
Good catch on my RB0 mistake, but that's not the problem. My encoder really is connected to RB0 for the INT interrupt (and RB6 for the other input); I just specified the incorrect port in the DIR spec. I fixed that error, but the program still crashes. It's not just that the interrupt affects the timing of things that use internal delay routines, it's an outright crash, or sometimes a restart.
Ok... i see one problem.
Your code uses strings, that are located at higher Bank, then uses PCLATH, and with last update GcBasic should save PCLATH or NOT clear it, but what it does is not saving PCLATH but clearing it (have a look to asm interrupt), I think program will crash for sure.
Then if PCLATH saving is no needed in interrupts, it should not be cleared.
Yes, I mentioned earlier that I still suspect the context-save. However, look at the EQU table I just posted...something's wrong there too.
It was the PCLATH clearing causing the problem. The string reading routines set PCLATH, then PCL, in order to read a character of a string from the program memory. If the interrupt occurred in the middle of reading a string, then PCLATH would be cleared, and when PCL was set the PIC would jump to a random location somewhere in the first 256 words of the program.
I've uploaded yet another update, which shouldn't clear PCLATH unless it's used in the interrupt, and that should then save PCLATH properly if it is.